返回

揭开手写 Promise 与 async/await 的神秘面纱,为你点亮异步编程的曙光

前端

在单线程运行机制下,javascript 引擎一经执行耗时过大的任务,必定会造成页面的阻塞,这显然会给用户体验带来负面影响。异步编程应运而生,试图解决阻塞难题。

Promise,javascript 内置的异步编程利器,它将回调嵌套的混乱转变成链式调用的优雅,极大地提升了异步编程的阅读性和可维护性。

手写 Promise 的实现过程,实乃探究异步编程核心奥义的必由之路。它能让你对 Promise 的工作原理有更为深入的了解。

class Promise {
    constructor(executor) {
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];
        executor(this.resolve.bind(this), this.reject.bind(this));
    }

    resolve(value) {
        if (this.state !== 'pending') {
            return;
        }
        this.state = 'fulfilled';
        this.value = value;
        this.onFulfilledCallbacks.forEach(callback => callback(this.value));
    }

    reject(reason) {
        if (this.state !== 'pending') {
            return;
        }
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(callback => callback(this.reason));
    }

    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };
        if (this.state === 'pending') {
            this.onFulfilledCallbacks.push(onFulfilled);
            this.onRejectedCallbacks.push(onRejected);
        } else if (this.state === 'fulfilled') {
            setTimeout(() => {
                onFulfilled(this.value);
            }, 0);
        } else {
            setTimeout(() => {
                onRejected(this.reason);
            }, 0);
        }
        return new Promise((resolve, reject) => {
            this.then(value => {
                try {
                    resolve(onFulfilled(value));
                } catch (err) {
                    reject(err);
                }
            }, reason => {
                try {
                    resolve(onRejected(reason));
                } catch (err) {
                    reject(err);
                }
            });
        });
    }
}

掌握了手写 Promise 的精髓,你已经成功踏出了异步编程的第一步。

async/await 作为 ES2017 引入的语法糖,它将异步编程的语法又向前推进了一步,让异步编程的操作看起来就像同步操作一样,极大地提高了异步编程的简洁性和易读性。

async function asyncFunction() {
  const value = await promise;
  return value;
}

使用 async/await 时,你需要注意以下几点:

  • async 函数总是返回一个 Promise。
  • await 只能用在 async 函数中。
  • await 后面跟的是一个 Promise 对象。
  • await 会暂停 async 函数的执行,直到 Promise 对象的状态变为 resolved 或 rejected。
  • await 会将 Promise 对象的状态结果作为返回值。

通过手写 Promise 和 async/await,你已经掌握了 javascript 异步编程的精髓,你的编程之路必将更上一层楼!