手写实现peomise

Promises/A+ 规范

作为 Modern JavaScript 基础设施的一部分,Promises 对前端开发者而言异常重要。

它是 async/await 语法的基础,是 JavaScript 中处理异步的标准形式。并且,未来的 Web API,只要是异步的,都会以 Promises 的形式出现。

如果不理解 Promises 相关的知识和运行机制,将来可能无法完成 Web 开发的日常工作。

因此,Promises 成为了前端面试中的必问问题之一。在网络上,也可以搜索到很多 Promises 的技术文章。甚至一些前端付费教程,以教你从零实现 Promises/A+ 规范作为卖点。

对于已经理解 Promises 的开发者来说,实现 Promises/A+ 是一个有益的训练。

前期工作

An open standard for sound, interoperable JavaScript promises

了解术语

1.1 “promise” is an object or function with a then method whose behavior conforms to this specification.
1.2 “thenable” is an object or function that defines a then method.
1.3 “value” is any legal JavaScript value (including undefined, a thenable, or a promise).
1.4 “exception” is a value that is thrown using the throw statement.
1.5 “reason” is a value that indicates why a promise was rejected.

规范的第一部分,描述了几个术语的意思。

promise 是一个包含 then 方法的对象或函数,该方法符合规范指定的行为。

thenable 是一个包含 then 方法和对象或者函数。

value 就是任意合法 JS 值。

exception 就是 throw 语句抛出的值。

reason 是一个指示 promise 为什么被 rejected 的值。

Promise状态

A promise must be in one of three states: pending, fulfilled, or rejected.

2.1 When pending, a promise:
  2.1.1 may transition to either the fulfilled or rejected state.
2.2 When fulfilled, a promise:
  2.2.1 must not transition to any other state.
  2.2.2 must have a value, which must not change.
2.3 When rejected, a promise:
  2.3.1 must not transition to any other state.
  2.3.1 must have a reason, which must not change.

promise 有 3 个状态,分别是 pending, fulfilled 和 rejected。

在 pending 状态,promise 可以切换到 fulfilled 或 rejected。

在 fulfilled 状态,不能迁移到其它状态,必须有个不可变的 value。

在 rejected 状态,不能迁移到其它状态,必须有个不可变的 reason。

Then方法

A promise must provide a then method to access its current or eventual value or reason.

A promise’s then method accepts two arguments:

promise.then(onFulfilled, onRejected)

promise 必须有 then 方法,接受 onFulfilled 和 onRejected 参数。

onFulfilled 的参数是 value,onRejected 函数的参数是 reason。

const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'

class Promise {
    
    
  constructor(executor) {
    
      // 执行器
    this.status = PENDING
    this.value = undefined
    this.reason = undefined

    let resolved = (value) => {
    
    
      if (this.status === PENDING) {
    
    
        this.value = value
        this.status = RESOLVED
      }
    }

    let rejected = (reason) => {
    
    
      if (this.status === PENDING) {
    
    
        this.reason = reason
        this.status = REJECTED
      }
    }

    try {
    
    
      executor(resolved, rejected)
    } catch (e) {
    
    
      rejected(e)
    }
  }
  then(onFulfilled, onRejected) {
    
    
    if (this.status === RESOLVED) {
    
    
      onFulfilled(this.value)
    }
    if (this.status === REJECTED) {
    
    
      onRejected(this.reason)
    }
  }
}

处理异步情况

class Promise {
    
    
  constructor {
    
    
    this.status = PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    let resolve = (value) => {
    
    
      if (this.status === PENDING) {
    
    
        this.value = value;
        this.status = RESOLVED;
        this.onFulfilledCallbacks.forEach(fn => fn()); // 订阅
      }
    }

    let reject = (reason) => {
    
    
      if (this.status === PENDING) {
    
    
        this.reason = reason;
        this.status = REJECTED;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    }

    try {
    
    
      executor(resolve, reject);
    } catch (e) {
    
    
      reject(e);
    }
  }

  then(onFulfilled, onRejected) {
    
    
    let promise2 = new Promise((resolve, reject) => {
    
    
      if (this.status === RESOLVED) {
    
    
        // 根据x的值来判断promise2的状态
        setTimeout(() => {
    
    
          let x = onFulfilled(this.value);
          resolvePromise(promise2, x, resolve, reject);
        }, 0);
        
      }
      if (this.status === REJECTED) {
    
    
        onRejected(this.reason);
      }
      // 处理异步的情况
      if (this.status === PENDING) {
    
     //发布订阅模式
        this.onFulfilledCallbacks.push(() => {
    
    
          onFulfilled(this.value);
        })
        this.onRejectedCallbacks.push(() => {
    
    
          onRejected(this.reason);
        })
      }
    })
    return promise2;
  }
}

The Promise Resolution Procedure

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pQiIDhqv-1614052331001)(…/…/.vuepress/public/img/promise.jpg)]

第一步,如果 result 是当前 promise 本身,就抛出 TypeError 错误。

第二步,如果 result 是另一个 promise,那么沿用它的 state 和 result 状态。

第三步,如果 result 是一个 thenable 对象。先取 then 函数,再 call then 函数,重新进入 The Promise Resolution Procedure 过程。

const resolvePromise = (promise2, x, resolve, reject) => {
    
    
  if (promise2 === x) {
    
    
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>]'));
  }
  if(typeof x === 'object' && x !== 'null' || typeof x === 'function') {
    
    
    try {
    
    
      let then = x.then;
      if (typeof then === 'function') {
    
    
        then.call(x, y => {
    
    
          resolve(y);
        }, r => {
    
    
          reject(r);
        })
      }
    } catch (e) {
    
    
      reject(e);
    }
    let then = x.then;
  } else {
    
    
    resolve(x);
  }
}

总结

能手写 promises 实现,对精通 promises 帮助不大。Promise/A+ 规范,重点围绕的是 How to implement。而不是 How to use。

想要精通 promises,还得在日常开发的各个异步场景中,多加思考和训练。

猜你喜欢

转载自blog.csdn.net/Beth__hui/article/details/113979969