提示💡

all(): 遍历、计数器、race(): 遍历、成功一个就返回。

手写代码

Promise . all

原生的 Promise. all 有什么特点?

  1. 特点1:接收一个可迭代对象
  2. 特点2:传入的数据中可以是普通数据,也可以是Promise对象
  3. 特点3:可迭代对象的promise是并行执行的
  4. 特点4:保持输入数组的顺序和输出数组的顺序一致
  5. 特点5:传入数组中只要有一个reject,立即返回reject
  6. 特点6:所有数据resolve之后返回结果
function myPromiseAll(iterable) {
    return new Promise((resolve,reject) => {
        const promises = Array.from(iterable);
        // 定义Promise对象resolve的数组
        const result = [];
        // 定义一个计数器用来判断是否所有的promise执行完毕
        let count = 0;
        // 并发执行每一个promise
        for (let i = 0; i < promises.length; i++) {
            Promise.resolve(promises[i]).then(res => {
                result[i] = res;
                count++;
                if (count === promises.length) {
                    resolve(result);
                }
            }).catch(err => reject(err))
        }
    })
}

Promise.race

 function myPromiseRace(promises) {
    return new Promise(function (resolve, reject) {
      for (let i = 0; i < promises.length; i++) {
        Promise.resolve(promises[i]).then(function (value) {
          return resolve(value)
        }, function (reason) {
          return reject(reason)
        })
      }
    })
  }

测试代码:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('p1'), 1000)
})
 
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('p2'), 5000)
})
 
Promise.race([p1, p2]).then(ret => {
   console.log(ret) // 'p1'
})

手写 promise

核心代码

// 记录 Promise 的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
 
/**
 * 运行一个微队列任务
 * 把传递的函数放到微队列中(模拟 vue 实现)
 * @param {Function} callback
 */
function runMicroTask(callback) {
  // 判断 node 环境
  // 为了避免「变量未定义」的错误,这里最好加上前缀 globalThis
  // globalThis 是一个关键字,指代全局对象,浏览器环境为 window,node 环境为 global
  if (globalThis.process && globalThis.process.nextTick) {
    // node
    process.nextTick(callback);
  } else if (globalThis.MutationObserver) {
    // 高版本浏览器
    const p = document.createElement('p');
    const observer = new MutationObserver(callback); // 可以做成单例,提高效率,这里简单实现
    observer.observe(p, {
      childList: true, // 观察该元素内部的变化
    });
    p.innerHTML = '1';
  } else {
    // 低版本浏览器
    setTimeout(callback, 0);
  }
}
 
/**
 * 判断一个数据是否是 Promise 对象
 * @param {any} obj
 * @returns
 */
function isPromise(obj) {
  // 必须是一个对象 && 必须有 then 函数
  return !!(obj && typeof obj === 'object' && typeof obj.then === 'function');
}
 
class MyPromise {
  /**
   * 创建一个 Promise
   * @param {Function} executor 任务执行器,立即执行
   */
  constructor(executor) {
    this._state = PENDING; // 状态
    this._value = undefined; // 数据
    this._handlers = []; // 处理函数形成的队列
 
    try {
      executor(this._resolve.bind(this), this._reject.bind(this));
    } catch (error) {
      // 处理错误
      this._reject(error);
      console.error(error);
    }
  }
 
  /**
   * 向处理队列中添加一个函数
   * @param {Function} executor 添加的函数
   * @param {String} state 该函数什么状态下执行
   * @param {Function} resolve 让 then 函数返回的 Promise 成功
   * @param {Function} reject 让 then 函数返回的 Promise 失败
   */
  _pushHandler(executor, state, resolve, reject) {
    this._handlers.push({ executor, state, resolve, reject });
  }
 
  /**
   * 根据实际情况,执行队列
   */
  _runHandlers() {
    if (this._state === PENDING) {
      // 目前任务仍在挂起
      return;
    }
    while (this._handlers[0]) {
      const handler = this._handlers[0];
      this._runOneHandler(handler);
      this._handlers.shift();
    }
  }
 
  /**
   * 处理一个 handler()
   * @param {Object} handler
   */
  _runOneHandler({ executor, state, resolve, reject }) {
    // 处理与当前状态 _state 相同的微任务
    runMicroTask(() => {
      if (this._state !== state) {
        // 状态不一致,不处理
        return;
      }
 
      if (typeof executor !== 'function') {
        // 传递后续处理并非一个函数,与之前的状态保持一致
        this._state === FULFILLED ? resolve(this._value) : reject(this._value);
        return;
      }
 
      try {
        const result = executor(this._value); // 返回结果有可能是 promise
        if (isPromise(result)) {
          result.then(resolve, reject);
        } else {
          resolve(result);
        }
      } catch (error) {
        reject(error);
        console.error(error);
      }
    });
  }
 
  /**
   * Promise A+ 规范的 then
   * @param {Function} onFulfilled
   * @param {Function} onRejected
   */
  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
      this._pushHandler(onRejected, REJECTED, resolve, reject);
      this._runHandlers(); // 执行队列(用户可能直接在 new Promise 中执行 resolve 或 reject,此时状态变化,需要立即执行队列)
    });
  }
 
  /**
   * 更改任务状态
   * @param {String} newState 新状态
   * @param {any} value 相关数据
   */
  _changeState(newState, value) {
    if (this._state !== PENDING) {
      // 目前状态已经更改
      return;
    }
 
    this._state = newState;
    this._value = value;
    this._runHandlers(); // 状态变化,执行队列
  }
 
  /**
   * 标记当前任务完成
   * @param {any} data 任务完成的相关数据
   */
  _resolve(data) {
    this._changeState(FULFILLED, data);
  }
 
  /**
   * 标记当前任务失败
   * @param {any} reason 任务失败的相关数据
   */
  _reject(reason) {
    this._changeState(REJECTED, reason);
  }
}

测试代码

// ------ 测试 1 ------
let pro1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject('失败');
  }, 1000);
});
 
let pro2 = pro1.then(function A1() { }, undefined);
setTimeout(() => {
  console.log(pro1);
  console.log(pro2);
}, 1500);
// 值穿透
// MyPromise { _state: 'rejected', _value: '失败', _handlers: [] }
// MyPromise { _state: 'rejected', _value: '失败', _handlers: [] }
 
 
// ------ 测试 2 ------
let pro3 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功');
  }, 1000);
});
 
let pro4 = pro3.then(function A1(data) {
  console.log(data);
  return new MyPromise((resolve, reject) => {
    resolve(1);
  });
});
setTimeout(() => {
  console.log(pro4);
}, 1500);
// 成功
// MyPromise { _state: 'fulfilled', _value: 1, _handlers: [] }
 
 
// ------ 测试 3(与官方 promise 互操作) ------
function delay(duraton) {
  return new MyPromise((resolve) => {
    setTimeout(resolve, duraton);
  });
}
(async function () {
  console.log('start');
  await delay(2000);
  console.log('end');
})();
 
// ------ 测试 4(与官方 promise 互操作) ------
const pro5 = new MyPromise((resolve) => {
  resolve(1);
});
 
pro5.then((data) => {
  console.log(data);
  return new Promise((resolve) => {
    resolve(2);
  })
}).then(data => {
  console.log(data);
});

完整代码

// 记录 Promise 的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
 
/**
 * 运行一个微队列任务
 * 把传递的函数放到微队列中(模拟 vue 实现)
 * @param {Function} callback
 */
function runMicroTask(callback) {
  // 判断 node 环境
  // 为了避免「变量未定义」的错误,这里最好加上前缀 globalThis
  // globalThis 是一个关键字,指代全局对象,浏览器环境为 window,node 环境为 global
  if (globalThis.process && globalThis.process.nextTick) {
    // node
    process.nextTick(callback);
  } else if (globalThis.MutationObserver) {
    // 高版本浏览器
    const p = document.createElement('p');
    const observer = new MutationObserver(callback); // 可以做成单例,提高效率,这里简单实现
    observer.observe(p, {
      childList: true, // 观察该元素内部的变化
    });
    p.innerHTML = '1';
  } else {
    // 低版本浏览器
    setTimeout(callback, 0);
  }
}
 
/**
 * 判断一个数据是否是 Promise 对象
 * @param {any} obj
 * @returns
 */
function isPromise(obj) {
  return !!(obj && typeof obj === 'object' && typeof obj.then === 'function');
}
 
class MyPromise {
  /**
   * 创建一个 Promise
   * @param {Function} executor 任务执行器,立即执行
   */
  constructor(executor) {
    this._state = PENDING; // 状态
    this._value = undefined; // 数据
    this._handlers = []; // 处理函数形成的队列
 
    try {
      executor(this._resolve.bind(this), this._reject.bind(this));
    } catch (error) {
      // 处理错误
      this._reject(error);
      console.error(error);
    }
  }
 
  /**
   * 向处理队列中添加一个函数
   * @param {Function} executor 添加的函数
   * @param {String} state 该函数什么状态下执行
   * @param {Function} resolve 让 then 函数返回的 Promise 成功
   * @param {Function} reject 让 then 函数返回的 Promise 失败
   */
  _pushHandler(executor, state, resolve, reject) {
    this._handlers.push({ executor, state, resolve, reject });
  }
 
  /**
   * 根据实际情况,执行队列
   */
  _runHandlers() {
    if (this._state === PENDING) {
      // 目前任务仍在挂起
      return;
    }
    while (this._handlers[0]) {
      const handler = this._handlers[0];
      this._runOneHandler(handler);
      this._handlers.shift();
    }
  }
 
  /**
   * 处理一个 handler()
   * @param {Object} handler
   */
  _runOneHandler({ executor, state, resolve, reject }) {
    // 处理与当前状态 _state 相同的微任务
    runMicroTask(() => {
      if (this._state !== state) {
        // 状态不一致,不处理
        return;
      }
 
      if (typeof executor !== 'function') {
        // 传递后续处理并非一个函数,与之前的状态保持一致
        this._state === FULFILLED ? resolve(this._value) : reject(this._value);
        return;
      }
 
      try {
        const result = executor(this._value); // 返回结果有可能是 promise
        if (isPromise(result)) {
          result.then(resolve, reject);
        } else {
          resolve(result);
        }
      } catch (error) {
        reject(error);
        console.error(error);
      }
    });
  }
 
  /**
   * Promise A+ 规范的 then
   * @param {Function} onFulfilled
   * @param {Function} onRejected
   */
  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
      this._pushHandler(onRejected, REJECTED, resolve, reject);
      this._runHandlers(); // 执行队列(用户可能直接在 new Promise 中执行 resolve 或 reject,此时状态变化,需要立即执行队列)
    });
  }
 
  /**
   * 仅处理失败的场景
   * @param {Function} onRejected
   */
  catch(onRejected) {
    return this.then(null, onRejected);
  }
 
  /**
   * 无论成功还是失败都会执行回调
   * @param {Function} onSettled
   */
  finally(onSettled) {
    return this.then(
      (data) => {
        onSettled();
        return data;
      },
      (reason) => {
        onSettled();
        throw reason;
      }
    );
  }
 
  /**
   * 更改任务状态
   * @param {String} newState 新状态
   * @param {any} value 相关数据
   */
  _changeState(newState, value) {
    if (this._state !== PENDING) {
      // 目前状态已经更改
      return;
    }
 
    // 下面这个判断是为了处理value为Promise的情况
    // 这一段代码课程中没有涉及,特此注释说明
    if (isPromise(value)) {
      value.then(this._resolve.bind(this), this._reject.bind(this));
      return;
    }
 
    this._state = newState;
    this._value = value;
    this._runHandlers(); // 状态变化,执行队列
  }
 
  /**
   * 标记当前任务完成
   * @param {any} data 任务完成的相关数据
   */
  _resolve(data) {
    this._changeState(FULFILLED, data);
  }
 
  /**
   * 标记当前任务失败
   * @param {any} reason 任务失败的相关数据
   */
  _reject(reason) {
    this._changeState(REJECTED, reason);
  }
 
  /**
   * 返回一个已完成的 Promise
   * 特殊情况:
   * 1. 传递的 data 本身就是 ES6 的 Promise 对象
   * 2. 传递的 data 是 PromiseLike(Promise A+),返回新的 Promise,状态和其保持一致即可
   * @param {any} data
   */
  static resolve(data) {
    if (data instanceof MyPromise) {
      return data;
    }
    return new MyPromise((resolve, reject) => {
      if (isPromise(data)) {
        data.then(resolve, reject);
      } else {
        resolve(data);
      }
    });
  }
 
  /**
   * 得到一个被拒绝的 Promise
   * @param {any}} reason
   */
  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }
 
  /**
   * 得到一个新的 Promise
   * 该 Promise 的状态取决于 proms 的执行
   * proms 是一个迭代器,包含多个 Promise
   * 全部 Promise 成功,则返回的 Promise 成功,数据为所有 Promise 成功的数据,并且顺序是按照传入的顺序排列
   * 只要有一个 Promise 失败,则返回的 Promise 失败,原因是第一个失败的 Promise 的原因
   * @param {iterator} proms
   */
  static all(proms) {
    return new MyPromise((resolve, reject) => {
      try {
        const results = [];
        let count = 0; // Promise 的总数,利用索引向 results 中放入结果,这样 results 里面的结果是有顺序的
        let fulfilledCount = 0; // 已完成的数量
 
        for (const p of proms) {
          let i = count;
          count++;
          MyPromise.resolve(p).then( // MyPromise.resolve(p) 包裹一下,p有可能不是 promise
            (data) => {
              fulfilledCount++;
              results[i] = data;
              if (fulfilledCount === count) {
                // 当前是最后一个 Promise 完成了
                resolve(results);
              }
            },
            reject
          );
        }
 
        if (count === 0) {
          resolve(results);
        }
      } catch (error) {
        reject(error);
        console.error(error);
      }
    });
  }
 
  /**
   * 等待所有的 Promise 有结果之后
   * 该方法返回的 Promise 完成
   * 并且按照顺序将所有结果汇总
   * @param {iterator} proms
   */
  static allSettled(proms) {
    const ps = [];
    for (const p of proms) {
      ps.push(
        // p.then: p 有可能不是 promise,所以用 MyPromise.resolve(p) 包裹一下
        MyPromise.resolve(p).then(
          (value) => ({
            status: FULFILLED,
            value,
          }),
          (reason) => ({
            status: REJECTED,
            reason,
          })
        )
      );
    }
    return MyPromise.all(ps);
  }
 
  /**
   * 返回的Promise与第一个有结果的一致
   * @param {iterator} proms
   */
  static race(proms) {
    return new MyPromise((resolve, reject) => {
      for (const p of proms) {
        MyPromise.resolve(p).then(resolve, reject);
      }
    });
  }
}

源码

//Promise 完整的实现
class Promise {
  callbacks = [];
  state = 'pending';//增加状态
  value = null;//保存结果
  constructor(fn) {
    fn(this._resolve.bind(this), this._reject.bind(this));
  }
  then(onFulfilled, onRejected) {
    return new Promise((resolve, reject) => {
      this._handle({
        onFulfilled: onFulfilled || null,
        onRejected: onRejected || null,
        resolve: resolve,
        reject: reject
      });
    });
  }
  catch(onError) {
    return this.then(null, onError);
  }
  finally(onDone) {
    if (typeof onDone !== 'function') return this.then();
 
    let Promise = this.constructor;
    return this.then(
      value => Promise.resolve(onDone()).then(() => value),
      reason => Promise.resolve(onDone()).then(() => { throw reason })
    );
  }
  static resolve(value) {
    if (value && value instanceof Promise) {
      return value;
    } else if (value && typeof value === 'object' && typeof value.then === 'function') {
      let then = value.then;
      return new Promise(resolve => {
        then(resolve);
      });
 
    } else if (value) {
      return new Promise(resolve => resolve(value));
    } else {
      return new Promise(resolve => resolve());
    }
  }
  static reject(value) {
    if (value && typeof value === 'object' && typeof value.then === 'function') {
      let then = value.then;
      return new Promise((resolve, reject) => {
        then(reject);
      });
 
    } else {
      return new Promise((resolve, reject) => reject(value));
    }
  }
  static all(promises) {
    return new Promise((resolve, reject) => {
      let fulfilledCount = 0
      const itemNum = promises.length
      const rets = Array.from({ length: itemNum })
      promises.forEach((promise, index) => {
        Promise.resolve(promise).then(result => {
          fulfilledCount++;
          rets[index] = result;
          if (fulfilledCount === itemNum) {
            resolve(rets);
          }
        }, reason => reject(reason));
      })
 
    })
  }
  static race(promises) {
    return new Promise(function (resolve, reject) {
      for (let i = 0; i < promises.length; i++) {
        Promise.resolve(promises[i]).then(function (value) {
          return resolve(value)
        }, function (reason) {
          return reject(reason)
        })
      }
    })
  }
  _handle(callback) {
    if (this.state === 'pending') {
      this.callbacks.push(callback);
      return;
    }
 
    let cb = this.state === 'fulfilled' ? callback.onFulfilled : callback.onRejected;
 
    if (!cb) {//如果then中没有传递任何东西
      cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
      cb(this.value);
      return;
    }
 
    let ret;
 
    try {
      ret = cb(this.value);
      cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
    } catch (error) {
      ret = error;
      cb = callback.reject
    } finally {
      cb(ret);
    }
 
  }
  _resolve(value) {
    if(this.state !== 'pending') return
    if (value && (typeof value === 'object' || typeof value === 'function')) {
      var then = value.then;
      if (typeof then === 'function') {
        then.call(value, this._resolve.bind(this), this._reject.bind(this));
        return;
      }
    }
 
    this.state = 'fulfilled';//改变状态
    this.value = value;//保存结果
    this.callbacks.forEach(callback => this._handle(callback));
  }
  _reject(error) {
    if(this.state !== 'pending') return
    this.state = 'rejected';
    this.value = error;
    this.callbacks.forEach(callback => this._handle(callback));
  }
}

扩展阅读