提示💡 all(): 遍历、计数器、race(): 遍历、成功一个就返回。 手写代码 Promise . all 原生的 Promise. all 有什么特点? 特点1:接收一个可迭代对象 特点2:传入的数据中可以是普通数据,也可以是Promise对象 特点3:可迭代对象的promise是并行执行的 特点4:保持输入数组的顺序和输出数组的顺序一致 特点5:传入数组中只要有一个reject,立即返回reject 特点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)); } } 扩展阅读 5、前端面试之道-手写 Promise