1. 术语

  • promise是一个有then办法的对象或函数,它的行为遵循本标准
  • thenable是一个定义了then办法的对象或函数
  • value是任意一个非法的JavaScript值,是promise状态为胜利时的值
  • exception是一个应用throw关键字抛出的异样值
  • reason是promise状态为失败时的值,示意promise失败的起因

2. 标准

2.1 Promise States

一个promise必须处于三种状态之一:pending, fulfilled, rejected.

  1. pending

    • 初始状态,可扭转(改变方式只有以下两种)
    • 可由pending变为fulfilled
    • 可由pending变为rejected
  2. fulfilled

    • 最终状态,不可变
    • 必须领有一个value,且不可变(===不可变)
  3. rejected

    • 最终状态,不可变
    • 必须领有一个reason,且不可变(===不可变)

2.2 then办法

一个promise必须提供then办法来拜访其以后或最终value或reason
一个promise的then办法接管两个参数:

promise.then(onFulfilled, onRejected)
  1. onFulfilledonRejected都是可选参数

    • 如果onFulfilled不是函数,则必须疏忽它
    • 如果onRejected不是函数,则必须疏忽它
  2. 如果onFulfilled是函数

    • 必须在promise变成fulfilled后调用onFulfilled, 并把value作为第一个参数
    • 在promise变成fulfilled之前, 不应该被调用
    • 只能被调用一次(所以在实现的时候须要一个变量来限度执行次数)
  3. 如果onRejected是函数

    • 必须在promise变成rejected后调用onRejected, 并把reason作为第一个参数
    • 在promise变成rejected之前, 不应该被调用
    • 只能被调用一次(所以在实现的时候须要一个变量来限度执行次数)
  4. 在执行上下文堆栈仅蕴含平台代码之前,不得调用 onFulfilled 或 onRejected。(即应该应用工作的形式来执行这两个回调函数,本次实现应用微工作形式)
  5. onFulfilled 和 onRejected 必须作为函数调用
  6. then办法在同一个promise上能够屡次调用

    • 当promise的状态变为fulfilled后,所有的 onFulfilled 回调都须要依照then的程序执行, 也就是依照注册程序执行(所以在实现的时候须要一个数组来寄存多个onFulfilled的回调)
    • 当promise状态变成 rejected 后,所有的 onRejected 回调都须要依照then的程序执行, 也就是依照注册程序执行(所以在实现的时候须要一个数组来寄存多个onRejected的回调)
  7. then办法必须返回一个promise

    • 如果 onFulfilled 或 onRejected 返回值 x,则须要调用Promise Resolution Procedure: [[Resolve]](promise2, x)
    • 如果 onFulfilled 或者 onRejected 执行时抛出异样e,promise2必须被reject,且把reason作为参数
    • 如果 onFulfilled 不是一个函数, promise2 以promise1的value 触发fulfilled
    • 如果 onRejected 不是一个函数, promise2 以promise1的reason 触发rejected

2.3 The Promise Resolution Procedure

[[Resolve]](promise, x)
  1. 如果 promise2 和 x 相等,那么 reject TypeError
  2. 如果 x 是一个 promsie

    • 如果x是pending态,那么promise必须要在pending,直到 x 变成 fulfilled or rejected.
    • 如果 x 被 fulfilled, fulfill promise with the same value.
    • 如果 x 被 rejected, reject promise with the same reason.
  3. 如果 x 是一个 object 或者 是一个 function

    • let then = x.then.
    • 如果 x.then 这步出错,那么 reject promise with e as the reason.
    • 如果 then 是一个函数,then.call(x, resolvePromiseFn, rejectPromise)
      其中resolvePromiseFn的入参是y, 执行 resolvePromise(promise2, y, resolve, reject);
      rejectPromise的入参是r, reject promise with r
      如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,前面的调用疏忽。
      如果调用then抛出异样e,如果resolvePromise或rejectPromise曾经被调用,那么疏忽;否则,reject promise with e as the reason
    • 如果 then 不是一个function. fulfill promise with x.

实现Promise

const PENDING = 'pending';const FULFILLED = 'fulfilled';const REJECTED = 'rejected';function MyPromise(fn) {    this._status = PENDING;    this.value = undefined;    this.reason = undefined;    this.FULFILLED_CALLBACK_LIST = [];    this.REJECTED_CALLBACK_LIST = [];    Object.defineProperty(this, 'status', {        configurable: true,        enumerable: true,        get: function() {            return this._status;        },        set: function(status) {            this._status = status;            switch(status) {                case FULFILLED: {                    this.FULFILLED_CALLBACK_LIST.forEach(callback => {                        callback(this.value);                    });                    break;                }                case REJECTED: {                    this.REJECTED_CALLBACK_LIST.forEach(callback => {                        callback(this.reason);                    });                    break;                }            }        }    });    try{        fn(this.resolve.bind(this), this.reject.bind(this));    } catch(e) {        this.reject(e);    }}MyPromise.prototype.resolve = function(value) {    if(this.status === PENDING) {        this.value = value;        this.status = FULFILLED;    }}MyPromise.prototype.reject = function(reason) {    if(this.status === PENDING) {        this.reason = reason;        this.status = REJECTED;    }}MyPromise.prototype.then = function(onFulfilled, onRejected) {    const realOnFulfilled = isFunction(onFulfilled) ? onFulfilled : value => value;    const realOnRejected = isFunction(onRejected) ? onRejected : reason => {        throw reason;    };    // const realOnRejected = isFunction(onRejected) ? onRejected : reason => reason;    const promise2 = new MyPromise((resolve, reject) => {        const queueFulfilledMicrotask = () => {            queueMicrotask(() => {                try{                    let x = realOnFulfilled(this.value);                    this.resolvePromise(promise2, x, resolve, reject);                } catch(e) {                    reject(e);                }            });        }        const queueRejectedMicrotask = () => {            queueMicrotask(() => {                try{                    let x = realOnRejected(this.reason);                    this.resolvePromise(promise2, x, resolve, reject);                } catch(e) {                    reject(e);                }            });        }        switch(this.status) {            case FULFILLED:                queueFulfilledMicrotask();                break;            case REJECTED:                queueRejectedMicrotask();                break;            case PENDING:            default:                this.FULFILLED_CALLBACK_LIST.push(queueFulfilledMicrotask);                this.REJECTED_CALLBACK_LIST.push(queueRejectedMicrotask);        }    });    return promise2;}MyPromise.prototype.catch = function(onRejected) {    return this.then(null, onRejected);}/** * The Promise Resolution Procedure  * [[Resolve]](promise, x) **/MyPromise.prototype.resolvePromise = function(promise2, x, resolve, reject) {    // If promise and x refer to the same object, reject promise with a TypeError as the reason.    if(promise2 === x) {        reject(new TypeError('The promise and the return value are the same'));    }        if(x instanceof MyPromise) { // If x is a promise, adopt its state        x.then((y) => {            this.resolvePromise(promise2, y, resolve, reject);        }, reject);    } else if(typeof x === 'object' || isFunction(x)) { // Otherwise, if x is an object or function        if(x === null) {            resolve(x);         }        // Let then be x.then        let then = null;        try{            then = x.then;        } catch(e) { // If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.            reject(e);        }        // If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise        if(isFunction(then)) {            // If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.            let called = false;            try{                then.called(x,                    y => {                        if(called) return;                        called = true;                        // If/when resolvePromise is called with a value y, run [[Resolve]](promise, y)                        this.resolvePromise(promise2, y, resolve, reject);                    },                    r => {                        if (called) return;                        called = true;                        // If/when rejectPromise is called with a reason r, reject promise with r.                        reject(r);                    });            } catch(e) { // If calling then throws an exception e                // If resolvePromise or rejectPromise have been called, ignore it.                if(called) return;                // Otherwise, reject promise with e as the reason.                reject(e);            }        }    } else { // If x is not an object or function, fulfill promise with x        resolve(x);    }}function isFunction(fn) {    return typeof fn === 'function';}// 测试const test = new MyPromise((resolve, reject) => {    console.log(1);    reject(111);}).then((value) => {    console.log(value);}).catch((reason) => {    console.log(reason);})console.log(2);

划重点

Promise实例化时传入的函数会立刻执行,then(...)中的回调函数onFulfilledonRejected须要异步提早调用。

要确保onFulfilledonRejected办法异步执行,且应该在then办法被调用的那一轮事件循环之后的新执行栈中执行。这个事件队列可采纳宏工作macro-task机制或微工作micro-task机制来实现。

参考文档:

  • Promises/A+标准
  • Promise Polyfill github仓库