JS 实现 Promise、Promise.all 和 Promise.race

3,132 阅读3分钟

1. Promise

  Promise 是承诺的意思,承诺在未来会有一个确切的答复,是 ES6 发布的异步编程的一种解决方案。 该承诺有三种状态:pending(等待)resolved(完成)rejected(拒绝) ,只能从 pending 变成其它两种状态,并且状态一旦变化后就不可改变。优点:有效改善异步编程中容易导致的回调地狱问题。缺点:Promise无法取消,错误需要通过回调函数捕获。

  • 定义三个状态常量
const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';
  • 实现 MyPromise
function MyPromise (fn) {
    const that = this;              // 代码可能异步执行,用于正确找到this
    that.value = null;              // 用于保存resolve、reject传入的值
    that.state = PENDING;
    that.resolvedCallbacks = [];    // 保存then中的回调,promise执行完后state的状态可能还是PENDING,
    that.rejectedCallbacks = [];    // 因此要把回调函数保存起来,等待state状态改变时执行
    
    // 实现resolve
    function resolve (value) {
        if (value instanceof MyPromise) {
            return value.then(resolve, reject);
        }
        setTimeout(() => {
            if (that.state === PENDING) {   // 只有PENDING状态才可以改变状态
                that.state = RESOLVED;
                that.value = value;
                that.resolvedCallbacks.forEach(cb => cb(that.value));   // 执行回调
            }
        }, 0)
    }
    
    // 实现reject
    function reject (value) {
        setTimeout(() => {
            if (that.state === PENDING) {
                that.state = REJECTED;
                that.value = value;
                that.rejectedCallbacks.forEach(cb => cb(that.value));
            }
        }, 0)
    }
    
    // 执行函数fn
    try {
        fn(resolve, reject);
    } catch (e) {
        reject(e);
    }
}
  • 实现 then 方法
MyPromise.prototype.then = function (onFulfilled, onRejected) {
    const that = this;
    // 参数为可选参数,首先判断两个参数是否为函数,如果不是函数,创建一个函数赋值给对应参数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
    onRejected = typeof onRejected === 'function' ? onRejected : v => { throw v };
    // 如果状态还是PENDING时,往回调函数中push函数,否则执行函数
    if (that.state === PENDING) {
        that.resolvedCallbacks.push(onFulfilled);
        that.rejectedCallbacks.push(onRejected);
    }
    if (that.state === RESOLVED) {
        onFulfilled(that.value);
    }
    if (that.state === REJECTED) {
        onRejected(that.value);
    }
}

2. Promise.all

将多个Promise实例包装成一个Promise实例,接收包含 Promise 对象或普通值的数组(或其它可迭代对象)作为参数,成功时返回值为Promise实例数组对应的结果数组,失败时返回第一个rejectedPromise实例的结果。

const p1 = new Promise(resolve => { setTimeout(resolve, 200, 1) });
const p2 = new Promise(resolve => { resolve(2) });
const p3 = 3;
console.log(Promise.all([p1, p2, p3]));     // [1, 2, 3]
Promise.prototype.all = function (promiseArr) {
    let resArr = [], count = 0, len = promiseArr.length;
    // 返回一个新的 Promise 实例
    return new Promise(function (resolve, reject) {
        for (let promise of promiseArr) {
            // 数组传进来的项可能不是一个Promise实例,使用Promise.resolve方法转换
            Promise.resolve(promise).then(function(res) {
                resArr[count] = res;
                count++;
                if (count === len) {
                    return resolve(resArr);
                }
            }, function (err) {
                return reject(err);
            })
        }
    })
}
  • 使用 async await 达到跟 Promise.all 同样效果的方法
var promiseQueue = async (arr) => {
    const res = [];
    for (let promise of arr) {
        res.push(await promise)
    }
    return await res;
}
promiseQueue([p1,p2,p3]).then(res => { console.log(res) }); // [1,2,3]

3. Promise.race

Promise.all 一样,Promise.race 也接收包含 Promise 对象或普通值的数组(或其它可迭代对象)作为参数,返回一个Promise实例对象。与 Promise.all 不同的是,一旦有一个 Promise 实例对象 resolve ,立即把这个resolve的值作为 Promise.race resolve的值。一旦有一个对象rejectPromise.race 也会立即reject

Promise.prototype.race = function (promiseArr) {
    return new Promise(function (resolve, reject) {
        for (let promise of promiseArr) {
            if (typeof promise === 'object' && typeof promise.then === 'function') {
                // 数组传进来的项是一个Promise实例,执行then方法。
                // resolve只有一个,那个实例对象最先执行完就会使用这个resolve
                promise.then(resolve, reject);
            } else {
                // 不是Promise实例对象直接返回当前值
                resolve(promise);
            }
        }
    })
}

4. Promise.resolve 和 Promise.reject 的使用

  • Promise.resolve(value)

返回一个以给定值解析后的Promise对象。

  1. 如果该值为promise,返回这个promise
  2. 如果这个值是带有"then" 方法的,返回的promise会“跟随”这个thenable的对象,采用它的最终状态;
  3. 否则返回的promise将以此值完成。
Promise.resolve("Success").then(function(value) {
  console.log(value); // "Success"
}, function(error) {
  // 不会被调用
});
  • Promise.reject(error)

静态函数Promise.reject返回一个被拒绝的Promise对象。通过使用Error的实例获取错误原因reason对调试和选择性错误捕捉很有帮助。

Promise.reject(new Error('fail')).then(function() {
  // not called
}, function(error) {
  console.error(error); // Stacktrace
});