你应该知道的Promise

125 阅读6分钟

Promise是什么? 

Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值.
  1. 处理异步操作。
  2. 得到异步操作的完成状态(成功/失败)和结果值。

为什么要使用Promise?

  1. 解决回调嵌套的问题(这不是关键点,个人理解)。
  2. 控制反转。

如何实现一个Promise?

Promise的实现遵循Promise/A+规范。

Promise States

一个Promise必须是以下三种状态的一种:pendingfulfilledrejected。

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

当处于等待时(pending),状态可以转换为已实现或已拒绝。

When pending, a promise:
 may transition to either the fulfilled or rejected state.

当被实现时(fulfilled),状态不可被再更改;必须有一个值,该值不能被更改。

When fulfilled, a promise: 
must not transition to any other state. 
must have a value, which must not change.

当被拒绝时(rejected),状态不可被再更改;必须有一个拒绝的理由,不能被更改。

When rejected, a promise: 
must not transition to any other state. 
must have a reason, which must not change.

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

const nextTick = (() => {    
const root = typeof window === "undefined" ? global : window;    
    if (typeof root.process === "object" && typeof root.process.nextTick === 'function') {        
        return fn => global.process.nextTick(fn);    
    }    
    return fn => setTimeout(fn, 0);
})();

class RPromise(){
    constructor(executor){        
        this.state = PENDING;
        this.value = undefined;
        this.reason = undefined;
    }

    resolve(value) {        
        if (this.state !== PENDING) {            
            return;        
        }        
        
        this.state = FULFILLED;        
        this.value = value;    
    }    

    reject(reason) {        
        if (this.state !== PENDING) {            
            return;        
        }        
        
        this.state = REJECTED;        
        this.reason = reason;    
    }
}

The then Method

一个Promise必须提供一个then的方法访问等待或实现或拒绝的方法。

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)

onFulfilled和onRejected是可选参数。如果onFulfilled不是函数,那么必须忽略。如果onRejected不是函数,必须忽略。

Both onFulfilled and onRejected are optional arguments: 
If onFulfilled is not a function, it must be ignored. 
If onRejected is not a function, it must be ignored.

如果onFulfilled是一个函数,那么一定在promise状态为fulfilled之后执行。promise的值为第一个参数,状态不为fulfilled时不可被调用,只可以被调用一次。

If onFulfilled is a function:
 it must be called after promise is fulfilled, with promise’s value as its first argument. 
it must not be called before promise is fulfilled. 
it must not be called more than once.

如果onRejected是一个参数,那么一定在promise状态为rejected之后执行。promise的拒绝原因为第一个参数,状态不为rejected时不可被调用,只可以被调用一次。

If onRejected is a function, 
it must be called after promise is rejected, with promise’s reason as its first argument.
it must not be called before promise is rejected.
it must not be called more than once.

onFulfilled和onRejected在上下文环境不仅包含当前代码内容前不可以调用。

onFulfilled or onRejected must not be called until the execution context stack contains only platform code

onFulfilled和onRejected作为普通函数进行调用,this在普通模式下指向window,严格模式下指向undefined。

onFulfilled and onRejected must be called as functions (i.e. with no this value).

同一个promise可以调用多次then。如果promise完成或被拒绝,那么必须按照then的注册顺序进行调用。

then may be called multiple times on the same promise. 
If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then.
 If/when promise is rejected, all respective onRejected callbacks must execute in the order of their originating calls to then.

then比如返回一个promise。

then must return a promise

promise2 = promise1.then(onFulfilled, onRejected);

如果onFulfilled或onRejected返回了一个值x,那么下个then会使用onFulfilled接收,并且值为x。

If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).

如果onFulfilled或onRejected引发了一个异常e,那么下个then必须使用onRejected接收,并且原因为e。

If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.

如果onFulfilled不是一个函数,并且promise已经执行完成。那么结果会被携带至下一个then,直至onFulfilled是一个函数。

If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.

如果onRejected不是一个函数,并且promise已经执行完成。那么错误原因会被携带至下一个then,直至onRejected是一个函数。

If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.

class RPromise(){
    constructor(executor){
        ...
        this.resolveQueue = [];
        this.rejectQueue = [];
    }


    ...

    then(){
        const _onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : RPromise.resolve;    
        const _onRejected = typeof onRejected === 'function' ? onRejected : RPromise.reject;        
        const _promise = new RPromise(() => { });

        try {            
            switch (this.state) {                
                case PENDING:                    
                    this.resolveQueue.push(_onFulfilled);                    
                    this.rejectQueue.push(_onRejected);                    
                break;                
                case FULFILLED:                    
                    nextTick(() => promiseResolutionProcedure(_promise, _onFulfilled(this.value)));                    
                break;                
                case REJECTED:                    
                    nextTick(() => promiseResolutionProcedure(_promise, _onRejected(this.reason)));                    
                break;            
            }        
        } catch (e) {            
            this.reject(e);        
        } finally {            
            return _promise;        
        }
    }
}

The Promise Resolution Procedure

Promise解决过程作为一个抽象的值可以接收一个Promise或一个值。如果表示为[[Resolve]](promise, x)。x是一个thenable,那么会尝试使用x的状态,前提是x的行为在某些程度上类似于promise。否则将使用值x实现promise。

The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as [[Resolve]](promise, x). If x is a thenable, it attempts to make promise adopt the state of x, under the assumption that x behaves at least somewhat like a promise. Otherwise, it fulfills promise with the value x.

如果要执行[[Resolve]](promise, x),比如符合以下步骤:

如果promise和x指向同一对象,那么promise以TypeError为理由拒绝。

If promise and x refer to the same object, reject promise with a TypeError as the reason.

如果x是一个promise,那么采用x的状态。如果x为等待状态,那么promise需要为同样的状态。如果x成功实现,那么promise需要返回相同的值。如果x失败,那么promise需要返回相同的失败理由。

If x is a promise, adopt its state :
If x is pending, promise must remain pending until x is fulfilled or rejected.
If/when x is fulfilled, fulfill promise with the same value. 
If/when x is rejected, reject promise with the same reason.

如果x是一个对象,那么then = x.then。如果x.then抛出异常e, 那么使用异常e作为promise拒绝的理由。

Otherwise, if x is an object or function, 
Let then be x.then.
If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.

如果then是一个函数,那么使用x作为this调用,第一个参数为resolvePromise,第二个参数为rejectPromise。

If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise

如果resolvePromise使用值y调用时,运行[[Resolve]](promise, y)。

If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).

如果rejectPromise使用理由r调用时,那么使用r拒绝promise(Promise.reject(r))。

If/when rejectPromise is called with a reason r, reject promise with r.

如果同时调用了resolvePromise和rejectPromise,或者对同一个参数调用了多次,那么以第一次调用为准,其它调用全都忽略。

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.

如果调用then引发异常e,当resolvePromise或rejectPromise被执行,那么忽略异常。否则将e作为错误原因调用reject。

If resolvePromise or rejectPromise have been called, ignore it. Otherwise, reject promise with e as the reason.

如果then不是一个函数,使用x来实现promise。

If then is not a function, fulfill promise with x.

如果x不是对象或函数,那么使用promise实现x。

If x is not an object or function, fulfill promise with x.

const promiseResolutionProcedure = (promise, result, async = true) => {    
    if (promise === result) {        
        promise._reject(new TypeError("Chaining cycle detected for promise"));        
        return;    
    }    
    /**     
     * 这里有两种情况     
     * 1. 接收到的是一个新的promise对象     
     * 2. 接收到的是一个thenable对象     
     */    
    if (result instanceof RPromise) {        
        switch (result.state) {            
            case FULFILLED:                
                nextTick(() => {                    
                    promise.resolve(result.value);                
                });                
            break;            
            case REJECTED:                
                nextTick(() => {                    
                    promise.reject(result.value);                
                });                
            break;            
            case PENDING:                
                const resolve = result.resolve;                
                const reject = result.reject;                
                result.resolve = function (value) {                    
                    resolve(value);                    
                    promise.resolve(value);                
                };                
                result.reject = function (reason) {                    
                    reject(reason);                    
                    promise.reject(reason);                
                };                
            break;        
        }        
        return;    
    }    
    if (result && typeof result.then === 'function') {        
        let isFlag = false;        
        const resolve = value => {            
            if (isFlag) {                
                return;            
            }            
            isFlag = true;            
            promiseResolutionProcedure(promise, value);        
        }        
        const reject = reason => {            
            if (isFlag) {                
                return;            
            }            
            isFlag = true;            
            promise.reject(reason);        
        }        
        const nextTemp = () => {            
            try {                
                result.then(resolve, reject);            
            } catch (e) {                
                resolve(e);            
            }        
        };  
      
        if (async) {            
            nextTick(nextTemp);        
        } else {            
            nextTemp();        
        }        
        return;    
    }    

    promise.resolve(result);
}

class RPromise(){
    constructor(executor) {
        ...

        promiseResolutionProcedure(this, { then: executor }, false);
    }
}

实现代码

github.com/ArtoriaSAMA…

参考文献

Promise/A+规范

Promise实现