手写一个简易版的Promise

1,767 阅读3分钟

一、了解Promise

Promise 是异步编程的一种解决方案,ES6新增的一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。

Promise有以下两个特点:

(1)Promise 的状态不受外界影响。Promise 翻译过来是承诺的意思,这个承诺会在未来有一个确切的答复,并且该承诺有三种状态,分别是:等待中pending、已完成 resolved、已失败rejected。它代表一个异步操作,只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

(2)Promise一旦由等待状态变成为其他状态就永远不能更改为其他状态了。也就是说,当状态从 Pending 变为 Resolved 或者 Rejected 后,状态就不能更改了。

new Promise((resolve, reject) => {
    resolve('resolve')
    reject('reject') // 这个reject无效
})

当我们在构造 Promise 的时候,构造函数内部的代码是立即执行的:

new Promise((resolve, reject) => {
    console.log(1);
    resolve('resolve')
})
console.log(2);

Promise 的链式调用:

new Promise(function(resolve, reject){
    resolve(1);
}).then(function(data){
    console.log(data);
    return 2; // 包装成 Promise.resolve(2)
}).then(function(data){
    console.log(data);
}).catch(function(err){
    console.log(err);
})

Promise 很好地解决了回调地狱的问题,使代码可以变得更加简洁优雅。

Promise 也存在一些缺点:(1) 它一旦新建就会立即执行,无法中途取消;(2) 错误是需要通过回调函数捕获。

二、手写一个简易版的Promise

首先,创建三个表示状态的常量:

const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';

搭建构造函数的框架:

function myPromise(fn) { // 传入的是一个函数
    // 定义一个常量that来缓存当前的this对象
    const that = this;
    // 初始状态是pending
    that.status = PENDING;
    // 定义一个变量来保存resolve或者reject传入的值
    that.param = null;
    // 定义两个数组来记录异步操作之后回来执行的函数(即保存then中的回调函数,等状态改变时执行)
    that.resolvedCallBacks = []; // 状态转为成功之后执行的函数
    that.rejectedCallBacks = []; // 状态转为失败之后执行的函数
    // 定义resolve函数
    function resolve() {

    }
    // 定义reject函数
    function reject() {
        
    }
    // 执行fn函数
    fn();
}

下面来完善resolvereject函数:

    // 定义resolve函数
    function resolve(param) {
        // 只有状态为初始状态时才执行
        if (that.status === PENDING) {
            that.status = RESOLVED; // 执行之后状态改为成功
            that.param = param; // 记录传入的参数
            // 遍历回调函数并执行
            that.resolvedCallBacks.map(function(callback){
                callback && callback(that.param);
            })
        }
    }
    // 定义reject函数
    function reject(param) {
        // 只有状态为初始状态时才执行
        if (that.status === PENDING) {
            that.status = REJECTED; // 执行之后状态改为失败
            that.param = param; // 记录传入的参数
            // 遍历回调函数并执行
            that.resolvedCallBacks.map(function(callback){
                callback && callback(that.param);
            })
        }
    }

执行 fn 函数时,把 resolvereject 当做参数传入,捕捉到错误后执行 reject 函数

    // 执行fn函数
    try {
        fn(resolve, reject);
    } catch(e) {
        reject(e);
    }

接下来实现 then 函数:

// then函数有两个参数onFulfilled, onRejected(参数为函数)
// 当前实例状态变成成功状态时,onFulfilled作为回调函数被调用
// 当前实例状态变成失败状态时,onRejected作为回调函数被调用
myPromise.prototype.then = function(onFulfilled, onRejected) {
    const that = this;
    // 当状态为初始状态时,把对应函数保存到对应回调函数数组中
    if (that.status === PENDING) {
        that.resolvedCallBacks.push(onFulfilled);
        that.rejectedCallBacks.push(onRejected);
    }
    // 当状态为成功状态时,执行onFulfilled
    if (that.status === RESOLVED) {
        onFulfilled(that.param);
    }
    // 当状态为成功状态时,执行onFulfilled
    if (that.status === REJECTED) {
        onRejected(that.param);
    }
}

以上就是简易版的 Promise 实现了,最后来简单的运行一下:

new myPromise(function(resolve, reject){
    resolve(1);
    // reject(2);
}).then(function(data) {
    console.log(data);
}, function(err) {
    console.log(err);
})