手写Promise - 完整

51 阅读5分钟
const p = new Promise((resolve, reject)=>{
   console.log('这里会立即执行');
   resolve('成功')
})

1.构造函数

  1. new Promise()创建实例,需要定义class
  2. 会先执行构造函数
  3. 构造函数接受一个回调函数((resolve, reject) => {...})作为参数
  4. 这个回调函数,接受resolve,reject两个函数参数,并且resolve,reject不是外部传递的,是自身的函数
  5. 构造函数内,会直接执行这个回调函数
class Prms{
    constructor(fun){
       const resolve = (result) =>{ console.log('resolve执行', result)};
       const reject = (result) =>{ console.log('reject执行', result)};
       fun(resolve,reject);
    }
}
const p = new Prms((resolve, reject)=>{
   console.log('这里会立即执行');
   resolve('成功')
})

2. 状态及结果

  1. 状态(pending, fulfilled, rejected),并且状态不可逆
  2. 结果,resolve,reject对应的成功/失败结果
  3. 这两个是实例属性
const PENDING = 'pending';
    const FULFILLED = 'fulfilled';
    const REJECTED = 'rejected';
    class Prms {
        state = PENDING;
        result = undefined;
        constructor(fun) { // 构造函数的this,就是实例对象
            const resolve = (result) => {
                if (this.state == 'pending') {
                    this.state = FULFILLED;
                    this.result = result;
                }
            };
            const reject = (result) => {
                if (this.state == 'pending') {
                    this.state = REJECTED;
                    this.result = result;
                }
            };
            fun(resolve, reject);
        }
    }
    const p = new Prms((resolve, reject) => {
        console.log('这里会立即执行');
        resolve('成功')
    })
    p.state  p.result

3. then方法 - 回调

p.then((res)=>{ 成功回调 }, (res)=>{ 失败回调 })

  • then为实例方法,接受两个回调函数作为参数,
  • 成功回调/失败回调,会接受reolve/reject的结果,即this.result
  • 回调函数是可选的,如果不传,会有默认处理
 then(onFulfilled, onRejected) {
      onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x;
      onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x };
      if (this.state === FULFILLED) {
         onFulfilled(this.result)
      } else if (this.state === REJECTED) {
         onRejected(this.result)
      }
}

3. then - 异步/多次调用

异步任务中,.then()调用时,状态还没改变

   const p = new Prms((resolve, reject) => {
        setTimeout(() => {
            console.log('这里会立即执行');
            resolve('成功结果')
        }, 1000)
    })
    p.then((res) => { console.log('then1成功', res) });
    p.then((res) => { console.log('then2成功', res) });   
  1. 添加实例属性handler,保存.then方法的回调函数
  2. 执行.then方法,如果状态还未改变,则存到handler中
  3. resolve/reject中,改变状态后,执行handler中的函数
#handlers = [] // [{onFulfilled, onRejected}, {...}]
const resolve = (result) => {
     if (this.state == 'pending') {
        this.state = FULFILLED;
        this.result = result;
        // 调用成功回调函数
        this.#handlers.forEach((fun) => fun.onFulfilled(result))
     }
};
 then(onFulfilled, onRejected) {
    ...
    if (this.state === FULFILLED) {
       onFulfilled(this.result)
    } else if (this.state === REJECTED) {
       onRejected(this.result)
    } else {
       // 保存回调函数
       this.#handlers.push({ onFulfilled, onRejected })
    }
 }

4. 异步任务

.then()方法是微任务,要在同步任务后执行

console.log('aaaa');
   const p = new Prms((resolve, reject) => {
       resolve('success');
   })
   p.then((res) => { console.log(res) })
   console.log('bbbb')

应该是 aaaa bbbb success

  • 封装一个异步执行的函数,接受一个函数为参数,异步执行
function runAsync(callback) {
   setTimeout(callback, 0)
}

.then中的方法需要异步

then(onFulfilled, onRejected) {
   ...
   if (this.state === FULFILLED) {
      runAsync(() => onFulfilled(this.result));
   } else if (this.state === REJECTED) {
      runAsync(() => onRejected(this.result));
   } else {
     this.#handlers.push({
         onFulfilled: () => runAsync(() => onFulfilled(this.result)),
         onRejected: () => runAsync(() => onRejected(this.result))
     })
   }
}

5. 链式编程

p.then(res => { return 2;}).then(res=> {...}, err=>{...})

  • .then()方法返回的结果,可以继续.then调用 --- .then()返回一个promise实例
  • .then()又可以获取上一个.then()返回的内容 --- promise实例resolve/reject
  • .then1()如果抛错,.then2()的onRejected获取执行
then(onFulfilled, onRejected) {
  ...
  1. 返回新promise实例
  const p2 = new Prms((resolve, reject) => {
    ---------创建promise,传递的回调函数,这里会立刻执行
    if (this.state === FULFILLED) {
       runAsync(() => {
         try {
           // 获取.then1()返回的结果
           const res = onFulfilled(this.result)
           // 成功 / 失败对应状态
           resolve(res);
          } catch (error) {
           reject(error);
          }
      });
     } else if (this.state === REJECTED) { ... }
    return p2;
  }
}
  1. 处理.then返回promise对象
...上述.then方法中
if (this.state === FULFILLED) {
  runAsync(() => {
    try {
         const res = onFulfilled(this.result)
         // 判断如果返回promise对象
         if (res instanceof Prms) {
            对象内部已经 resolve/reject过,这里.then直接获取对应结果
            res.then(res => resolve(res), err => reject(err))
         } else {
            resolve(res);
         }
     } catch (error) {
        reject(error);
     }
  });
}
  1. 处理重复引用 p.then()回调函数中返回值,等于 p.then()的返回值
const p1 = new Promise((resolve) => {
   resolve('pp');
})
const p2 = p2.then((res) => {
   return p2;
})
正常是要抛错的

image.png

// p2为.then方法返回的结果,res为.then方法回调返回的结果
const res = onFulfilled(this.result);
if (res === p2) {
   throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
  1. rejected状态处理
  • 同fulfilled状态的操作
  • 可以把.then返回promise实例的操作封装一下
 function resolvePromise(p2, r, resolve, reject) {
    if (r === p2) {
       throw new TypeError('Chaining cycle detected for promise #<Promise>')
    }
    if (r instanceof Prms) {
      r.then(res => resolve(res), err => reject(err))
    } else {
       resolve(r);
    }
}
if (this.state === FULFILLED) {
   runAsync(() => {
     try {
        const r = onFulfilled(this.result)
        resolvePromise(p2, r, resolve, reject);
     } catch (error) {
        reject(error);
     }
   });
} else if (this.state === REJECTED) {
    runAsync(() => {
       try {
         const r = onRejected(this.result)
         resolvePromise(p2, r, resolve, reject);
      } catch (error) {
       reject(error);
      }
   });
}
  1. pending状态处理 操作同上
else {              
   this.#handlers.push({
      onFulfilled: () => runAsync(() => {
       try {
           const r = onFulfilled(this.result)
           resolvePromise(p2, r, resolve, reject);
         } catch (error) {
           reject(error);
         }
     }),
     onRejected: () => runAsync(() => {
       try {
           const r = onRejected(this.result)
           resolvePromise(p2, r, resolve, reject);
         } catch (error) {
             reject(error);
         }
     })
  })
}

6. 实例方法

  1. catch - 就是调用.then方法,只传第二个参数
catch(onRejected) {
   return this.then(undefined, onRejected)
}
 --------构造函数执行要捕获一下错误,确保可以走到catchtry {
   fun(resolve, reject);
 } catch (error) {
   reject(error)
 }
  1. finally
finally(onFinally) {
    return this.then(onFinally, onFinally)
}

7. 静态方法

  1. resolve
  • 传入的值如果是promise对象,直接返回
  • 普通值,转为promise返回(fulfilled状态)
static resolve(value){
  if(value instanceof Prms){
     return value
  }
  return new Prms((resolve)=>{
     resolve(value)
  })
}
  1. reject
  • 直接返回一个已拒绝的对象
static reject(value){
  return new Prms((undefined, reject)={
     reject(value)
  })
}
  1. race
  • 返回一个promise
  • 传入的参数是数组
  • 等待第一个promise状态确定
static race(promises){
  return new Prms(()=>{
   if(!Array.isArray(promises)){
     reject(new TypeError('Argument is not iterable'))
   }
   // 等待状态确定
   promises.forEach((p)=>{
     // 数组元素可能不是promise对象
     Prms.resolve(p).then(
       res=>resolve(res),
       err=>reject(err)
     )
   })
  }) 
}
  1. all
  • 接受一个参数(数组),返回一个promise对象
  • 当传入的所有promise都成功,返回的promise也成功,返回一个(成功的值的)数组
  • 任意一个失败,则返回的promise失败,带有第一个失败的promise原因
static all(promises){
  return new Prms((resolve, reject)=>{
    if (!Array.isArray(promises)) {
      reject(new TypeError('Argument is not iterable'))
    }
    // 空数组直接兑现
    promises.length ===0 && resolve(promises)
    const results = [];
    let count = 0;
    
    promises.forEach((p, index) => {
      Prms.resolve(p).then(
        res => {
          // 不用push, 异步顺序可能不一致
          results[index] = res;
          // 判断状态是否全部改变
          count ++;
          count === promises.length && resolve(results)
        },
        err => {
          reject(err)
        }
      )
    })
  })
}