手写 promise(渡一教育版)

101 阅读2分钟

渡一教育袁进老师版本的手写 promise,逻辑蛮清晰的。 视频可以去 b 站找。 自己写一遍确实清晰很多。

const PENDING = 'pending';  
const FULFILLED = 'fulfilled';  
const REJECTED = 'rejected';  
  
class Mypromise {  
  #state = PENDING;  
  #result = undefined;  
  #handlers = [];  
  #promise = undefined;  
  #changeState = (state, result) => {  
    this.#state = state;  
    this.#result = result;  
    this.#run();  
  }  
  constructor(executor) {  
    const resolve = (value) => {  
      this.#changeState(FULFILLED, value);  
    }  
    const reject = (reason) => {  
      this.#changeState(REJECTED, reason);  
    }  
    try {  
      executor(resolve, reject);  
    }catch (error) {  
      reject(error);  
    }  
  }  #runMicroTask(func){  
    if(typeof process !== 'undefined' && typeof process.nextTick === 'function') {  
      process.nextTick(func);  
    } else if (typeof MutationObserver !== 'undefined') {  
      const observer = new MutationObserver(func);  
      const textNode = document.createTextNode('1');  
      observer.observe(textNode, {  
        characterData: true  
      });  
      textNode.data = '2';  
    } else {  
      setTimeout(func, 0);  
    }  
  }  
  #isPromiseLike(value) {  
    if(value !== null && typeof value === 'object' || typeof value === 'function') {  
      return typeof value.then === 'function';  
    }  
    return false;  
  }  
  #runOne(callback, resolve, reject){  
    this.#runMicroTask(() => {  
      if(typeof callback !== 'function') {  
        resolve(this.#result);  
      } else {  
        try{  
          const data = callback(this.#result);  
          if(this.#isPromiseLike(data)) {  
            if(data === this.#promise){  
              throw new TypeError('Chaining cycle detected for promise');  
            }  
            data.then(resolve, reject);  
          } else {  
            resolve(data);  
          }  
        }catch (error) {  
          reject(error);  
        }  
      }    })  
  }  
  #run(){  
    if(this.#state === PENDING) return;  
    while(this.#handlers.length) {  
      const {resolve, onFulfilled, onRejected, reject} = this.#handlers.shift();  
      if(this.#state === FULFILLED) {  
        this.#runOne(onFulfilled, resolve, reject);  
      } else if (this.#state === REJECTED) {  
        this.#runOne(onRejected, resolve, reject);  
      }  
    }  }  
    then(onFulfilled, onRejected) {  
	    this.#promise = new Mypromise((resolve, reject) => {  
	      this.#handlers.push({  
	        onFulfilled,  
	        onRejected,  
	        resolve,  
	        reject  
	      });  
      this.#run();  
    })  
    return this.#promise;  
  }  
  static resolve(value) {  
    // 传入promise直接返回promisse  
    if (value instanceof Mypromise) return value;  
    // 如果是promiseLike,执行then  
    // 注意静态方法不能调用实例方法,得新建一个实例,还把状态改变方法暴露出来  
    let _resolve, _reject;  
    const p = new Mypromise((resolve, reject) => {  
      _resolve = resolve;  
      _reject = reject;  
    });  
    if (p.#isPromiseLike(value)) {  
      value.then(_resolve, _reject);  
    } else {  
      _resolve(value);  
    }  
    return p;  
  }  
  // 静态方法,结果包到promise里  
  static reject(reason) {  
    return new Mypromise((resolve, reject) => {  
      reject(reason);  
    })  
  }  
  // 不是A+标准,是ES6加的  
  // Promise.prototype.catch  
  catch(onRejected) {  
    // 失败的回调  
    return this.then(undefined, onRejected);  
  }  
  // Promise.prototype.finally  
  finally(onFinally) {  
    // 无论成功失败都会执行的回调  
    // 不会传入参数,返回值要穿透  
    return this.then(  
      (data) => {  
        onFinally();  
        return data;  
      },  
      (err) => {  
        onFinally();  
        throw err;  
      })  
  }  
  static all(promiseList){  
    return new Mypromise((resolve, reject) =>{  
      let result = [];  
      let count = 0;  
      promiseList.forEach((promise, index) => {  
        Mypromise.resolve(promise).then(value => {  
          result[index] = value;  
          count++;  
          if(count === promiseList.length) {  
            resolve(result);  
          }  
        }).catch(reason => {  
          reject(reason);  
        })  
      })  
    })  
  }  
}  
  
// 测试代码  
let promise = new Mypromise((resolve, reject) => {  
  setTimeout(() => {  
    resolve('成功');  
  }, 1000);  
});  
  
promise.then(null,reason => {  
  console.log(reason); // 输出:成功  
  return Promise.resolve('成功2');  
}).then(value => {  
  console.log(value); // 输出:成功!  
});  
Mypromise.all([new Mypromise((resolve, reject) => {  
  setTimeout(() => {  
    resolve(1);  
  })  
}),2,3]).then(value => {  
  console.log(value); // 输出:[1,2,3]  
})