ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

实现一个Promise.all,了解它到底在做什么

实现一个Promise.all,了解它到底在做什么 Promise.all到底在做什么根据MDN的描述试着实现一下/** * Promise工具函数_withResolvers, 返回一个对象: * 其中包含一个Promise实例: promise以及用来改变这个实例promise状态的 resolve 和 reject 函数 * 由于node环境不支持Promise.withResolvers(),所以我们选择手动实现 * returns {promise, resolve, reject} */ Promise._withResolvers function _withResolvers() { let resolve; let reject; let promise new Promise((_resolve, _reject) { resolve _resolve; reject _reject; }); return {promise, resolve, reject}; } /** * 判断入参是否为PromiseLike: 是ES官方定义实现的Promise实例 or 符合Promise A规范 --带有一个then方法的 promise * param {*} target * returns */ function isPromiseLike(target) { return target typeof target.then function; } /** * Promise.all 的显示实现 * param {*} tasks tasks is an iterable object: Array、Set... */ Promise._all function _all(tasks) { // 在node环境下需要自己实现 withResolvers // promise是_all方法的返回值 const {promise, resolve, reject} Promise._withResolvers(); let total 0; // 一共有多少个待执行的任务 let finished 0; // 已完成的任务数量 let result []; // 返回值当所有的任务正确完成后按任务的加入顺序进行放置每一个Promise // 因为Promise.all的参数要求是一个可迭代对象所以可以用 for of 进行遍历 for(const task of tasks) { let index total; // 总任务数量1, 并记录每个任务的索引 /** * 注意每一次进行迭代时我们都单独声明一个处理函数_resolve用于操作result * .then()中_resolve函数的操作是异步执行的调用_resolve 时total 已经能代表总的任务数量了 * 但由于 _resolve 创建时可以访问外部作用域所以index就代表了从 0 开始的结果下标 * 我们不知道result[index]何时被赋值也不知道哪一个index是最后设置的 */ const _resolve res { // 当任务正确结束的时候根据传入的顺序放置结果并且记录已经完成的总数量 result[index] res; finished; if(finished total) { // _resolve 方法执行时这里的total已经能代表tasks的总数量了 resolve(result); } } /** * 每一轮迭代Promise.resolve(task)会创建一个新的Promise * 如果这个Promise被完成则调用_resolve函数将其加入结果集 * 如果这个Promise被拒绝则会调用reject */ Promise.resolve(task).then(_resolve, reject); } // 如果任务列表为空直接将promise的状态设置为fulfilled if(total 0) { resolve(result); } return promise; }我们将官网的用例拿来测试一下const p1 Promise.resolve(3); const p2 1337; const p3 new Promise((resolve, reject) { setTimeout(() { resolve(foo); }, 100); }); Promise._all([p1, p2, p3]).then((values) { console.log(values); // [3, 1337, foo] });ok,完成。
返回列表