手写promise A+、catch、finally、all、allsettled、any、race

Table of contents

handwritten promise

Synchronized version

1. The construction method of Promise receives an executor(), and the executor callback is executed immediately when new Promise() is issued.

2. The asynchronous tasks inside executor() are put into the macro/microtask queue, waiting for execution

3. Management of status and results

Status can only be changed once

4.then() calls success/failure callback

catch is the abbreviation for failed callback

Asynchronous version

1. Cache success and failure callbacks

2.then add Pending processing

3. Call the callback function in resolve and reject

Calling the same promise's then multiple times

1. Cache success and failure callback queues

2. When pengding, then() collects dependencies and puts the success/failure callbacks into the success/failure queue.

3. Trigger resolve/reject, take the callbacks from the success/failure queue and execute them in sequence

then chain call: return a Promise object

When then returns itself, an error is thrown in the loop call

Wait for the returned promise to be initialized: queueMicrotask microtask

catch errors

executor error

thenerror

then([onFulfilled, onRejected]) parameters are optional

then penetration: ignore non-function parameters, non-functions will be executed synchronously

Static call resolve, reject

full version

Promise A+ standard version of resolvePromise

catch

finally

Concurrent requests

template

all

allSettled

any

race


handwritten promise

同步版

1. Pass the resolve and reject functions of promise to the instance.

 constructor(executor){
    // executor 是一个执行器,进入会立即执行
    // 并传入resolve和reject方法
    executor(this.resolve, this.reject) 
  }

2. The instance passes values ​​to the resolve and reject functions.

resolve('success')
reject('err')
// 新建 test.js

// 引入我们的 MyPromise.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
   resolve('success')
   reject('err')
})

promise.then(value => {
  console.log('resolve', value)
}, reason => {
  console.log('reject', reason)
})

// 执行结果:resolve success

1.PromiseThe constructor receives an executor callback executor()and new Promise()immediately executes it.

class Promise{
 // 构造方法接收一个回调
  constructor(executor){
      executor();

}

2.executor()Internal asynchronous tasks are placed into the macro/microtask queue, waiting for execution

  // Why do we need to use arrow functions for resolve and reject?
  // If called directly, the ordinary function this points to window or undefined
  // Use arrow functions to make this point to the current instance object

class MyPromise {
  constructor(executor){
    // executor 是一个执行器,进入会立即执行
    // 并传入resolve和reject方法
    executor(this.resolve, this.reject) 
  }

  // 更改成功后的状态
  resolve = () => {}
  // 更改失败后的状态
  reject = () => {}
}

3. Management of status and results

Status can only be changed once
// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

// 新建 MyPromise 类
class MyPromise {
  constructor(executor){
  ...
  }

  // 储存状态的变量,初始值是 pending
  status = PENDING;

  // 成功之后的值
  value = null;
  // 失败之后的原因
  reason = null;

  // 更改成功后的状态
  resolve = (value) => {
    // 只有状态是等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态修改为成功
      this.status = FULFILLED;
      // 保存成功之后的值
      this.value = value;
    }
  }

  // 更改失败后的状态
  reject = (reason) => {
    // 只有状态是等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态成功为失败
      this.status = REJECTED;
      // 保存失败后的原因
      this.reason = reason;
    }
  }
}

4. then()调用Success/failure callback

catchIs 调用the abbreviation for failure callback
// MyPromise.js

then(onFulfilled, onRejected) {
  // 判断状态
  if (this.status === FULFILLED) {
    // 调用成功回调,并且把值返回
    onFulfilled(this.value);
  } else if (this.status === REJECTED) {
    // 调用失败回调,并且把原因返回
    onRejected(this.reason);
  }
}

Asynchronous version

// test.js

const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 2000); 
})

promise.then(value => {
  console.log('resolve', value)
}, reason => {
  console.log('reject', reason)
})

// 同步版没有打印信息(执行到then时,状态还是pending)
// 异步版等待 2s 输出 resolve success

1. Cache success and failure callbacks

// MyPromise 类中新增
// 存储成功回调函数
onFulfilledCallback = null;
// 存储失败回调函数
onRejectedCallback = null;

2.then add Pending processing

// MyPromise.js

then(onFulfilled, onRejected) {
     ...
     if (this.status === PENDING) {
    // ==== 新增 ====
    // 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
    // 等到执行成功失败函数的时候再传递
    this.onFulfilledCallback = onFulfilled;
    this.onRejectedCallback = onRejected;
  }
}

3. Call the callback function in resolve and reject

// MyPromise.js

// 更改成功后的状态
resolve = (value) => {
  // 只有状态是等待,才执行状态修改
  if (this.status === PENDING) {
    // 状态修改为成功
    this.status = FULFILLED;
    // 保存成功之后的值
    this.value = value;
    // ==== 新增 ====
    // 判断成功回调是否存在,如果存在就调用
    this.onFulfilledCallback && this.onFulfilledCallback(value);
  }
}

多次调用同一个promise的then

// test.js

const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 2000); 
})

promise.then(value => {
  console.log(1)
  console.log('resolve', value)
})
 
promise.then(value => {
  console.log(2)
  console.log('resolve', value)
})

promise.then(value => {
  console.log(3)
  console.log('resolve', value)
})
//单个回调:
 3
resolve success
//回调队列:
1
resolve success
2
resolve success
3
resolve success

1. Cache success and failure callback queues

// MyPromise.js

// 存储成功回调函数
// onFulfilledCallback = null;
onFulfilledCallbacks = [];
// 存储失败回调函数
// onRejectedCallback = null;
onRejectedCallbacks = [];

2.pengding时,then()收集依赖, put the success/failure callback into the success/failure queue

// MyPromise.js

then(onFulfilled, onRejected) {
  // 判断状态
  if (this.status === FULFILLED) {
    // 调用成功回调,并且把值返回
    onFulfilled(this.value);
  } else if (this.status === REJECTED) {
    // 调用失败回调,并且把原因返回
    onRejected(this.reason);
  } else if (this.status === PENDING) {
    // ==== 新增 ====
    // 因为不知道后面状态的变化,这里先将成功回调和失败回调存储起来
    // 等待后续调用
    this.onFulfilledCallbacks.push(onFulfilled);
    this.onRejectedCallbacks.push(onRejected);
  }
}

3.Trigger resolve/reject, take the callbacks from the success/failure queue and execute them sequentially

// MyPromise.js

// 更改成功后的状态
resolve = (value) => {
  // 只有状态是等待,才执行状态修改
  if (this.status === PENDING) {
    // 状态修改为成功
    this.status = FULFILLED;
    // 保存成功之后的值
    this.value = value;
    // ==== 新增 ====
    // resolve里面将所有成功的回调拿出来执行
    while (this.onFulfilledCallbacks.length) {
      // Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空
      this.onFulfilledCallbacks.shift()(value)
    }
  }
}

then chain call: return a Promise object

Take fulfilled as an example, the same applies to other

// MyPromise.js

class MyPromise {
  ...
  then(onFulfilled, onRejected) {
    // 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
    const promise2 = new MyPromise((resolve, reject) => {
      // 这里的内容在执行器中,会立即执行
      if (this.status === FULFILLED) {
        // 获取成功回调函数的执行结果
        const x = onFulfilled(this.value);
        // 传入 resolvePromise 集中处理
        resolvePromise(x, resolve, reject);

      } ...
    }) 
    
    return promise2;
  }
}

function resolvePromise(x, resolve, reject) {
  // 判断x是不是 MyPromise 实例对象
  if(x instanceof MyPromise) {
    // 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected
    // x.then(value => resolve(value), reason => reject(reason))
    // 简化之后
    x.then(resolve, reject)
  } else{
    // 普通值
    resolve(x)
  }
}

When then returns itself, an error is thrown in the loop call

// test.js

const promise = new Promise((resolve, reject) => {
  resolve(100)
})
const p1 = promise.then(value => {
  console.log(value)
  return p1
})

function resolvePromise(promise2, x, resolve, reject) {
  // 如果相等了,说明return的是自己,抛出类型错误并返回
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
 ...
}
Wait for the returned promise to be initialized: queueMicrotask microtask

// MyPromise.js

class MyPromise {
  ......
  then(onFulfilled, onRejected) {
    const promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
    
        // 创建一个微任务等待 promise2 完成初始化
        queueMicrotask(() => {
          // 获取成功回调函数的执行结果
          const x = onFulfilled(this.value);
          // 传入 resolvePromise 集中处理
          resolvePromise(promise2, x, resolve, reject);
        })  
      } ...
    }) 
    
    return promise2;
  }
}

catch errors

 try {
         异步操作
} catch (error) {
          reject(error)
}  

executor error

// MyPromise.js

constructor(executor){
  // ==== 新增 ====
  // executor 是一个执行器,进入会立即执行
  // 并传入resolve和reject方法
  try {
    executor(this.resolve, this.reject)
  } catch (error) {
    // 如果有错误,就直接执行 reject
    this.reject(error)
  }
}

thenerror

// MyPromise.js

then(onFulfilled, onRejected) {
  // 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
  const promise2 = new MyPromise((resolve, reject) => {
    // 判断状态
    if (this.status === FULFILLED) {
      // 创建一个微任务等待 promise2 完成初始化
      queueMicrotask(() => {
        try {
          // 获取成功回调函数的执行结果
          const x = onFulfilled(this.value);
          // 传入 resolvePromise 集中处理
          resolvePromise(promise2, x, resolve, reject);
        } catch (error) {
          reject(error)
        }  
      })  
    } ...
  }) 
  
  return promise2;
}

then([onFulfilled, onRejected]) parameters are optional

then  penetration : ignore non-function parameters, non-functions will be executed synchronously

Promise.resolve(1)
  .then(2)//传入值
  .then(Promise.resolve(3))//传入promise对象
  .then(console.log)//传入函数
1

Promise.resolve()
  .then(new Promise(r => {
    setTimeout(() => {
      r(console.log(1))
    }, 1000)
  }))
  .then(new Promise(r => {
    setTimeout(() => {
      r(console.log(2))
    }, 1000)
  }))
  .then(new Promise(r => {
    setTimeout(() => {
      r(console.log(3))
    }, 1000)
  }))
延迟1秒后,打印123

different from the following

// MyPromise.js

then(onFulfilled, onRejected) {
  // 如果不传,就使用默认函数
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
  onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};

  // 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
  const promise2 = new MyPromise((resolve, reject) => {
  ......
}

Static call resolve, reject

// MyPromise.js

MyPromise {
  ......
  // resolve 静态方法
  static resolve (parameter) {
    // 如果传入 MyPromise 就直接返回
    if (parameter instanceof MyPromise) {
      return parameter;
    }

    // 转成常规方式
    return new MyPromise(resolve =>  {
      resolve(parameter);
    });
  }

  // reject 静态方法
  static reject (reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }
}

full version

// MyPromise.js

// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

// 新建 MyPromise 类
class MyPromise {
  constructor(executor){
    // executor 是一个执行器,进入会立即执行
    // 并传入resolve和reject方法
    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }

  // 储存状态的变量,初始值是 pending
  status = PENDING;
  // 成功之后的值
  value = null;
  // 失败之后的原因
  reason = null;

  // 存储成功回调函数
  onFulfilledCallbacks = [];
  // 存储失败回调函数
  onRejectedCallbacks = [];

  // 更改成功后的状态
  resolve = (value) => {
    // 只有状态是等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态修改为成功
      this.status = FULFILLED;
      // 保存成功之后的值
      this.value = value;
      // resolve里面将所有成功的回调拿出来执行
      while (this.onFulfilledCallbacks.length) {
        // Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空
        this.onFulfilledCallbacks.shift()(value)
      }
    }
  }

  // 更改失败后的状态
  reject = (reason) => {
    // 只有状态是等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态成功为失败
      this.status = REJECTED;
      // 保存失败后的原因
      this.reason = reason;
      // resolve里面将所有失败的回调拿出来执行
      while (this.onRejectedCallbacks.length) {
        this.onRejectedCallbacks.shift()(reason)
      }
    }
  }

  then(onFulfilled, onRejected) {
    const realOnFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    const realOnRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};

    // 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
    const promise2 = new MyPromise((resolve, reject) => {
      const fulfilledMicrotask = () =>  {
        // 创建一个微任务等待 promise2 完成初始化
        queueMicrotask(() => {
          try {
            // 获取成功回调函数的执行结果
            const x = realOnFulfilled(this.value);
            // 传入 resolvePromise 集中处理
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error)
          } 
        })  
      }

      const rejectedMicrotask = () => { 
        // 创建一个微任务等待 promise2 完成初始化
        queueMicrotask(() => {
          try {
            // 调用失败回调,并且把原因返回
            const x = realOnRejected(this.reason);
            // 传入 resolvePromise 集中处理
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error)
          } 
        }) 
      }
      // 判断状态
      if (this.status === FULFILLED) {
        fulfilledMicrotask() 
      } else if (this.status === REJECTED) { 
        rejectedMicrotask()
      } else if (this.status === PENDING) {
        // 等待
        // 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
        // 等到执行成功失败函数的时候再传递
        this.onFulfilledCallbacks.push(fulfilledMicrotask);
        this.onRejectedCallbacks.push(rejectedMicrotask);
      }
    }) 
    
    return promise2;
  }

  // resolve 静态方法
  static resolve (parameter) {
    // 如果传入 MyPromise 就直接返回
    if (parameter instanceof MyPromise) {
      return parameter;
    }

    // 转成常规方式
    return new MyPromise(resolve =>  {
      resolve(parameter);
    });
  }

  // reject 静态方法
  static reject (reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  // 如果相等了,说明return的是自己,抛出类型错误并返回
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  // 判断x是不是 MyPromise 实例对象
  if(x instanceof MyPromise) {
    // 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected
    // x.then(value => resolve(value), reason => reject(reason))
    // 简化之后
    x.then(resolve, reject)
  } else{
    // 普通值
    resolve(x)
  }
}

module.exports = MyPromise;

Promise A+ standard version of resolvePromise

It is required to judge whether x is an object or function. If it is satisfied, then judge whether x.then exists. This can be understood as judging whether x is a promise. The functions here are actually  x instanceof MyPromise similar to those in our handwritten version.

// MyPromise.js

function resolvePromise(promise, x, resolve, reject) {
  // 如果相等了,说明return的是自己,抛出类型错误并返回
  if (promise === x) {
    return reject(new TypeError('The promise and the return value are the same'));
  }

  if (typeof x === 'object' || typeof x === 'function') {
    // x 为 null 直接返回,走后面的逻辑会报错
    if (x === null) {
      return resolve(x);
    }

    let then;
    try {
      // 把 x.then 赋值给 then 
      then = x.then;
    } catch (error) {
      // 如果取 x.then 的值时抛出错误 error ,则以 error 为据因拒绝 promise
      return reject(error);
    }

    // 如果 then 是函数
    if (typeof then === 'function') {
      let called = false;
      try {
        then.call(
          x, // this 指向 x
          // 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
          y => {
            // 如果 resolvePromise 和 rejectPromise 均被调用,
            // 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
            // 实现这条需要前面加一个变量 called
            if (called) return;
            called = true;
            resolvePromise(promise, y, resolve, reject);
          },
          // 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
          r => {
            if (called) return;
            called = true;
            reject(r);
          });
      } catch (error) {
        // 如果调用 then 方法抛出了异常 error:
        // 如果 resolvePromise 或 rejectPromise 已经被调用,直接返回
        if (called) return;

        // 否则以 error 为据因拒绝 promise
        reject(error);
      }
    } else {
      // 如果 then 不是函数,以 x 为参数执行 promise
      resolve(x);
    }
  } else {
    // 如果 x 不为对象或者函数,以 x 为参数执行 promise
    resolve(x);
  }
}

catch

//catch方法其实就是执行一下then的第二个回调
catch(rejectFn) {
  return this.then(undefined, rejectFn)
}

finally

Since the final state of the promise cannot be known, finallythe callback function does not receive any parameters. It is only used when it is executed regardless of the final result.

 finally(callBack) {
      return this.then(callBack, callBack)
  }

Concurrent requests

template

  /**
     * @param {iterable} promises 一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入
     * @returns 
     */
static 并发(promises) {
// 参数校验
if (Array.isArray(promises)) {
     let result = []; // 存储结果
     let count = 0; // 计数器

     if (promises.length === 0) {
// 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise
         return resolve(promises);
         //C. 返回一个 已失败(already rejected) 状态的 Promise。
         return reject(new AggregateError('All promises were rejected'));
     }

  return new myPromise((resolve, reject) => {
   promises.forEach((item, index) => {
      myPromise.resolve(item).then(
                value => {
                 count++;
                 // 每个promise执行的结果存储在result中
                 
                    //A.记录所有reject/fulfilled,需要区分状态
                    result[index] = {
                               status: 'fulfilled',
                               value
                                }
                    //B.只记录fulfilled
                    result[index] = value
                 // 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)
                 count === promises.length && resolve(result);
                 //C.只要一个成功
                 resolve(value);
                 },
                 reason => {
                 //A.记录所有reject
                 count++;
                 result[index] = {
                               status: 'rejected',
                               reason
                                }
                 count === promises.length && resolve(result);
                 //B.一旦reject
                 reject(reason);     
                 //C.全reject
                 count++;
                 errors.push(reason);
                 //AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。
                 count === promises.length && reject(new AggregateError(errors));
                 })
   })

} else {
  return reject(new TypeError('Argument is not iterable'))
}

}

all

/**
* 如果传入的 promise 中有一个失败(rejected),
* Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成
*/     
static all(promises) {
return new myPromise((resolve, reject) => {
   promises.forEach((item, index) => {
      myPromise.resolve(item).then(
                value => {
                 count++;
                 // 每个promise执行的结果存储在result中
                 result[index] = value;
                 // 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)
                 count === promises.length && resolve(result);
                 },
                 reason => {
                 reject(reason);                         
                 })
   })
}

allSettled

static allSettled(promises) {
return new myPromise((resolve, reject) => {
   promises.forEach((item, index) => {
      myPromise.resolve(item).then(
                value => {
                 count++;
                 // 每个promise执行的结果存储在result中
                 //A.记录所有reject/fulfilled,需要区分状态
                 result[index] = {
                               status: 'fulfilled',
                               value
                                }
                 // 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)
                 count === promises.length && resolve(result);
                 },
                 reason => {
                 //A.记录所有reject
                 count++;
                 result[index] = {
                               status: 'rejected',
                               reason
                                }
                 count === promises.length && resolve(result);           
                 })
   })
}

any

static any(promises){
 return new myPromise((resolve, reject) => {
   promises.forEach((item, index) => {
      myPromise.resolve(item).then(
                value => {
                 //C.只要一个成功
                 resolve(value);
                 },
                 reason => {
                 //C.全reject
                 count++;
                 errors.push(reason);
                 //AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。
                 count === promises.length && reject(new AggregateError(errors));
                 })
   })
}

race

//race方法(返回最早执行完的promise结果,无论成功与否)
Promise.race = function(promises){
   return new myPromise((resolve, reject) => {
              // 如果传入的迭代promises是空的,则返回的 promise 将永远等待。
              if (promises.length > 0) {
                  promises.forEach(item => {
                       myPromise.resolve(item).then(resolve, reject);
                  })
              }
          }
      })

Implement all instance methods and static methods of Promise by handwriting. Let’s see how Promise.all, Promise.race and Promise.any are implemented - Nuggets

Starting from a Promise interview question that made me sleepless, we will conduct an in-depth analysis of Promise implementation details - Nuggets

Guess you like

Origin blog.csdn.net/qq_28838891/article/details/134679261