简要介绍:Promise允许我们通过链式调用的方式来解决“回调地狱”的问题,特别是在异步过程中,通过Promise可以保证代码的整洁性和可读性。

本文主要介绍一下Promise/A+规范,并在此规范的基础上,自己实现一个Promise。

一、Promise的使用

在了解Promise规范之前,我们知道主流的高版本浏览器已经支持ECMA中的Promise.

创建一个promise实例:

let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("success");
    }, 3000);
    console.log("this is a promise");
});
p1.then(value => {
    console.log(value);
});
// 输出:
// 立马打印:this is a promise
// 延迟3000ms后打印:success

上述是一个promise的实例,输出内容为,“this is a promise”,延迟3000ms后,输出"success"。

从上述的例子可以看出,promise方便处理异步操作。此外promise还可以链式的调用:

let p2 = new Promise((resolve, reject) => {
    resolve();
});
p2.then(...).then(...).then(...);

此外Promise除了then方法外,还提供了Promise.resolve、Promise.all、Promise.race等等方法。

二、Promise/A+规范

Promise/A+规范大致有以下内容:

1.术语
(1)"promise"是一个对象或者函数,该对象或者函数有一个then方法
(2)"thenable"是一个对象或者函数,用来定义then方法
(3)"value"是promise状态成功时的值
(4)"reason"是promise状态失败时的值
我们明确术语的目的,是为了在自己实现promise时,保持代码的规范性

2.要求
(1)一个promise必须有3个状态,pending,fulfilled(resolved),rejected。
当处于pending状态的时候,可以转移到fulfilled(resolved)或者rejected状态。当处于fulfilled(resolved)状态或者rejected状态的时候,就不可变。
promise英文译为承诺,也就是说promise的状态一旦发生改变,就永远是不可逆的。

(2)一个promise必须有一个then方法,then方法接受两个参数:

promise1.then(onFulfilled, onRejected);

其中onFulfilled方法表示状态从pending —> fulfilled(resolved)时所执行的方法,而onRejected表示状态从pending —> rejected所执行的方法。

(3)为了实现链式调用,then方法必须返回一个promise

promise2 = promise1.then(onFulfilled, onRejected);

三、实现一个符合Promise/A+规范的Promise

了解了Promise/A+规范之后,下面我们来看如何实现一个Promise。
首先构造一个myPromise函数,关于所有变量和函数名,应该与规范中保持相同。

1.v1.0 初始版本myPromise

function myPromise(constructor) {
    let self = this;
    self.status = 'pending';
    self.value = undefined; // 成功时的值
    self.reason = undefined; // 失败时的值
    function resolve (value) {
        // 1.确保状态只能由 pending 改为 resolved
        if (self.status === 'pending') {
            self.value = value;
            self.status = 'resolved';
        }
    }
    function reject (reason) {
        // 2.确保状态只能由 pending 改为 rejected
        if (self.status === 'pending') {
            self.reason = reason;
            self.status = 'rejected';
        }
    }
    try {
        constructor(resolve, reject);
    } catch(e) {
        reject(e);
    }
}

同时,需要在myPromise的原型上定义链式调用的then方法:

myPromise.prototype.then = function (onFullfilled, onRejected) {
    let self = this;
    switch (self.status) {
        case 'resolved':
            onFullfilled(self.value);
            break;
        case 'rejected':
            onRejected(self.reason);
            break;
    }
};

上述就是一个初始版本的myPromise,在myPromise里发生状态改变,然后在相应的then方法里面根据不同的状态可以执行不同的操作。

let mp = new myPromise(function (resolve, reject) {
    resolve(1);
    // reject('err msg');
});
mp.then(function (res) {
    console.log(res);
}, function (err) {
    console.log(err);
});
// 输出 1

但是这里myPromise无法处理异步的resolve。比如:

let mp1 = new myPromise(function (resolve, reject) {
    setTimeout(() => {
        resolve(2);
    }, 2000);
});
mp1.then(function (res) {
    console.log(res);
});
// 无输出

2.v2.0基于观察模式实现

...


lxcan
337 声望32 粉丝