Promise详解

Event Loop 事件循环机制

  • JavaScript 是单线程语言,浏览器环境下的 JavaScript 代码执行依赖于浏览器提供的事件循环机制(Event Loop)。事件循环机制中包含以下两个队列:

    • 宏队列:包含 script 脚本、setTimeoutsetIntervalI/OUI rendering
    • 微队列:包含 PromiseMutationObserver
  • 简而言之,每次取出第一个宏任务执行前,都要将微队列清空

Promise 的基本使用

new Promise(executor)

  • executor 执行器函数,内部逻辑是同步执行的
  • 接收 resolvereject 两个函数参数,resolve 函数调用后 promise 变为成功状态,reject 函数调用后变为失败状态。若是执行器中抛出了异常,变为失败状态
  • promise 的状态只能改变一次

then(onFulfilled, onRejected)

  • then 方法调用时,Web Api 创建一个处理器,当 promise 有结果状态,且 then 参数中指定了对应的回调函数后,对应的回调函数插入微队列中等待执行
  • 两个回调函数的默认值:onFulfilled = value => valueonRejected = reason => { throw reason; }
  • then 方法的返回值为一个新的 promise,其结果、状态由回调函数的返回值决定:
    • 回调函数返回一个 promise 时,then 返回的 promise 的结果状态,和回调函数返回的 promise 的结果状态相同。因此想中断 promise 链,可以在回调函数中返回一个 pendingpromise
    • 回调函数返回非 promise 时,then 返回的 promise 状态为成功,结果为回调函数的返回值
    • 回调函数抛出任何值,then 返回的 promise 状态为失败,结果为回调函数抛出的值

catch(onRejected)

  • catch 方法是 then 方法的语法糖,相当于 then(undefined, onRejected)

Promise.resolve(value)

  • valuepromise 时,直接返回,否则包装为一个成功的 promise 返回

Promise.reject(reason)

  • reasonpromise 时,直接返回,否则包装为一个失败的 promise 返回

Promise.all(array)

  • 如果 array 中每一项都成功,则返回一个数组,对应的值为成功的值
  • 如果有一项为失败,则返回失败的值
  • 如果有一项不为 promise,则在数组中原样返回

Promise.race(array)

  • 返回 array 中第一个完成的 promise 的结果

async 函数和 await 表达式

async 函数

  • 返回值为 Promise 对象,结果由 async 函数的返回值决定

await 表达式

  • 如果表达式是 Promise 对象,await 返回其成功的值
  • 如果 Promise 可能会失败,则应放在 try catch 里捕获处理
  • 如果表达式是其他值,await 直接返回
  • 必须写在 async 函数中

自定义 Promise

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
    constructor(executor) {
        // 异常处理
        try {
            executor(this.resolve, this.reject);
        } catch (error) {
            this.reject(error);
        }
    }

    status = PENDING;
    value = undefined;
    reason = undefined;
    // 一个promise实例,then方法能多次调用,因此需要一个队列用于缓存
    onFulfilled = [];
    onRejected = [];

    // 箭头函数,因为resolve函数是直接调用的,在class中使用箭头函数可以把this绑定到实例对象上
    resolve = value => {
        if (this.status === PENDING) {
            this.status = FULFILLED;
            this.value = value;
            // 调用成功的回调
            while (this.onFulfilled.length) {
                this.onFulfilled.shift()(this.value);
            }
        }
    };

    reject = reason => {
        if (this.status === PENDING) {
            this.status = REJECTED;
            this.reason = reason;
            // 调用失败的回调
            while (this.onRejected.length) {
                this.onRejected.shift()(this.reason);
            }
        }
    };

    // 普通函数,因为this已通过实例对象的调用而绑定
    // 成功回调函数不传时默认为value => value
    // 失败回调函数不传时默认为reason => { throw reason; }
    then(
        onFulfilled = value => value,
        onRejected = reason => {
            throw reason;
        }
    ) {
        // then方法返回一个promise实例对象,以支持链式调用
        let returnPromise = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                // returnPromise在new Promise完成后才能获取到,因此使用setTimeout变为异步代码
                setTimeout(() => {
                    // then的回调函数中异常处理
                    try {
                        // 下一个then方法的成功回调函数接收的值
                        let x = onFulfilled(this.value);
                        resolvePromise(returnPromise, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                }, 0);
            } else if (this.status === REJECTED) {
                // returnPromise在new Promise完成后才能获取到,因此使用setTimeout变为异步代码
                setTimeout(() => {
                    // then的回调函数中异常处理
                    try {
                        // 下一个then方法的失败回调函数接收的值
                        let x = onRejected(this.reason);
                        resolvePromise(returnPromise, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                }, 0);
            }
            // 调用then时依然是pending状态,缓存成功和失败的回调
            else {
                this.onFulfilled.push(() => {
                    // returnPromise在new Promise完成后才能获取到,因此使用setTimeout变为异步代码
                    setTimeout(() => {
                        // then的回调函数中异常处理
                        try {
                            // 下一个then方法的成功回调函数接收的值
                            let x = onFulfilled(this.value);
                            resolvePromise(returnPromise, x, resolve, reject);
                        } catch (error) {
                            reject(error);
                        }
                    }, 0);
                });
                this.onRejected.push(() => {
                    // returnPromise在new Promise完成后才能获取到,因此使用setTimeout变为异步代码
                    setTimeout(() => {
                        // then的回调函数中异常处理
                        try {
                            // 下一个then方法的失败回调函数接收的值
                            let x = onRejected(this.reason);
                            resolvePromise(returnPromise, x, resolve, reject);
                        } catch (error) {
                            reject(error);
                        }
                    }, 0);
                });
            }
        });
        return returnPromise;
    }

    catch(onRejected) {
        return this.then(undefined, onRejected);
    }

    // 无论promise成功还是失败,都会调用
    // 返回一个promise,可以获取到成功或失败的值
    finally(callback) {
        return this.then(
            value => {
                return MyPromise.resolve(callback()).then(() => value);
            },
            reason => {
                return MyPromise.resolve(callback()).then(() => {
                    throw reason;
                });
            }
        );
    }

    static all(array) {
        return new MyPromise((resolve, reject) => {
            // 计数器,当数组中有异步代码时,保证resolve方法在所有异步任务结束后才被调用
            let count = 0;
            let res = [];
            for (let i = 0; i < array.length; i++) {
                if (array[i] instanceof MyPromise) {
                    array[i].then(
                        value => {
                            res[i] = value;
                            count++;
                            if (count === array.length) {
                                resolve(res);
                            }
                        },
                        reason => {
                            reject(reason);
                        }
                    );
                } else {
                    res[i] = array[i];
                    count++;
                    if (count === array.length) {
                        resolve(res);
                    }
                }
            }
        });
    }

    static race(array) {
        return new MyPromise((resolve, reject) => {
            for (let i = 0; i < arr.length; i++) {
                array[i].then(
                    value => {
                        resolve(value);
                    },
                    reason => {
                        reject(reason);
                    }
                );
            }
        });
    }

    static resolve(value) {
        return value instanceof MyPromise ? value : new MyPromise(resolve => resolve(value));
    }

    static reject(reason) {
        return reason instanceof MyPromise ? reason : new MyPromise(reject => reject(reason));
    }
}

function resolvePromise(returnPromise, x, resolve, reject) {
    // 如果x是promise实例,判断x的状态,决定调用resolve还是reject
    if (x instanceof MyPromise) {
        // 回调函数返回的promise,不能是then函数返回的promise
        if (x === returnPromise) {
            reject(new TypeError(''));
            return;
        }
        x.then(
            value => resolve(value),
            reason => reject(reason)
        );
    } else {
        resolve(x);
    }
}

Promise详解
https://www.reimu747.ink/post/20200508.html
作者
Reimu747
发布于
2020年5月8日
许可协议