JavaScript Promise 使用教程
目录一、promise的理解和使用promise是什么?promise的基本使用为什么要用promise?如何使用promise二、Promise的关键问题如何改变Promise状态一个Promise指定多个成功/失败的回调函数都会调用吗?改变promise状态和指定回调函数谁先谁后promise.then()返回的新的promise的结果状态由什么决定promise如何串联多个操作任务promise异常穿透中断promise链三、自定义promise函数版本class版本四、 如何按顺序执行多个Promise方法一使用.then()链式调用方法二使用async/await方法三使用Promise.all()五、不定数目的Promise的串行调用方式1. reduce:比较简单和常见的方式方式2. async 循环 await方式3. 普通循环方式4. 递归方式5. for await of方式6. generator六、JS异步之宏队列和微队列Promise 教程 Promise - JavaScript | MDN一、promise的理解和使用promise是什么?抽象表达promise是JS中进行异步编程的新的解决方案具体的表达从语法上来说promise是一个构造函数从功能上来说promise对象用来封装一个异步操作并可以获取其结果promise的状态改变pending变为resolvedpending变为rejected说明只有这两种且一个promise对象只能改变一次无论变为成功还是失败都会有一个结果数据成功的结果数据一般称为value失败的结果数据一般称为reasonpromise的基本流程promise的基本使用script typetext/javascript // 1.创建一个新的promise对象 const p new Promise((resolve , reject) { //执行器函数, 是一个同步回调 console.log(执行 excutor) // 2.执行异步任务 setTimeout(() { const time Date.now() //如果当前时间为偶数代表成功否则失败 // 3.1 如果成功了调用resolve(value) if(time % 2 0){ resolve(成功的数据time time) }else{ //3.2 如果失败了调用reject(reason) reject(失败的数据,time time) } },1000) }) console.log(new promise()执行之后) p.then( value {//接受得到成功的value数据 onResolved console.log(成功的回调,value); }, reason {//接受得到失败的reason数据 onRejected console.log(失败的回调,reason); } ) /script为什么要用promise?指定回调函数的方式更加灵活旧的必须在启动异步任务之前指定promise: 启动异步任务 返回promise对象 给promise对象绑定回调函数(甚至可以在异步任务结束后指定)支持链式调用可以解决回调地狱问题什么是回调地狱回调函数嵌套调用外部回调函数异步执行的结果是嵌套的回调函数执行的条件回调地狱的缺点不便于阅读 / 不便于异常处理解决方案 promise链式调用终极解决方案 async/await如何使用promisepromise构造函数:Promise(excutor){}excutor函数执行器 (resolve,reject) {}resolve函数内部定义成功时调用的函数 value {}reject函数内部定义失败时我们调用的函数 reason {}说明excutor会在Promise内部立即同步回调异步操作在执行器中执行Promise.prototype.then方法(onResolved , onRejected) {}onResolved函数成功的回调函数 value {}onRejected函数失败的回调函数 reason {}说明指定用于得到成功value的成功回调函数和用于得到失败reason的失败回调函数返回一个新的promise对象Promise.prototype.catch方法(onRejected) {}onRejected函数失败的回调函数 (reason) {}then的语法糖相当于then(undefined,onRejected)Promise.resolve方法value {}value: 成功的数据或者promise对象说明返回一个成功/失败的promise对象Promise.reject方法(reason) {}reason:失败的原因说明返回一个失败的promise对象Promise.all方法(promises) {}promises:包含n个promise的数组说明返回一个新的promise只有所有的promise都成功才算成功只要有一个失败了就直接失败Promise.race方法(promises) {}promises:包含n个promise数组说明返回一个新的promise第一个完成的promise的结果状态就是最终的状态script typetext/javascript new Promise((resolve , reject) { //执行异步任务 setTimeout(() { //resolve(成功的数据) reject(失败的数据) }, 1000) }).then( value { console.log(onResolved()1, value); } ).catch( reason { console.log(onRejected()1 , reason); } ) // 产生一个成功值为1的promise对象 const p1 new Promise((resolve , reject) { resolve(1) }) const p2 Promise.resolve(2) //产生一个失败值为3的promise对象 const p3 Promise.reject(3) p1.then( value { console.log(value); }) p2.then( value { console.log(value); } ) p3.catch( reason { console.log(reason); }) const pAll Promise.all([p1 , p2]) pAll.then( values { console.log(all onResolved(),values);//[1,2] }, reasons { console.log(all onRejected(),reasons);//3 } ) // race 比赛返回第一个成功或失败的数据 const Prace Promise.race([p3, p2, p1]) Prace.then( value { console.log(on Resolved(), value); }, reason { console.log(on Rejected(),reason); } ) /script二、Promise的关键问题如何改变Promise状态resolve(value):如果当前是pendding就会变为resolvedreject(reason):如果当前为pendding就会变为rejected抛出异常如果当前为pendding就会变为rejected一个Promise指定多个成功/失败的回调函数都会调用吗?当promise改变为对应状态时都会调用script typetext/javascript const p new Promise((resolve , reject) { // resolve(1) //promise变为resolved成功状态 // reject(2) // promise变为rejected失败状态 // throw new Error(出错) //抛出异常promise变为rejected失败状态reason为抛出的error throw 3 //抛出异常promise变为rejected失败状态reason为抛出的3 }) p.then( value { console.log(value1,value); }, reason { console.log(reason1, reason); } ) p.then( value { console.log(value2,value); }, reason { console.log(reason2,reason); } ) /script改变promise状态和指定回调函数谁先谁后都有可能正常情况下是先指定回调再改变状态但也可以先改变状态再指定回调如何先改变状态再指定回调在执行器中直接调用resolve()/reject()延长更长时间才调用then()什么时候才能得到数据如果先指定的回调那当状态发送改变时回调函数就会调用得到数据如果先改变状态那当指定回调时回调函数就会调用得到数据script typetext/javascript // 常规上先指定回调会改变状态 new Promise((resolve , reject) { setTimeout(() { resolve(1) // 后改变的状态(同时指定数据),异步执行回调函数 },1000) }).then( //先指定回调函数保存当前指定的回调函数 value {}, reason { console.log(reason , reason); } ) new Promise((resolve , reject) { resolve(1) // 先改变的状态(同时指定数据) }).then( //后指定回调函数异步执行回调函数 value {}, reason { console.log(reason , reason); } ) /scriptpromise.then()返回的新的promise的结果状态由什么决定简单表达式有then()指定的回调函数执行的结果决定详细表达如果抛出异常新promise变为rejectedreason为抛出异常如果返回的是非promise任意值新promise变为resolved,value为返回值如果返回的是另一个新的promise此promise的结果就会成为新promise的结果script typetext/javascript new Promise((resolve , reject) { resolve(1) }).then( value { console.log(value,value);//1 //return value //return Promise.resolve(3) //return Promise.reject(4) // throw 5 }, reason { console.log(reason,reason); } ).then( value { console.log(value1,value);//undefined }, reason { console.log(reason1,reason); } ) /scriptpromise如何串联多个操作任务promise的then返回一个新的promise看一看成then的链式调用使用then的链式调用串联多个同步异步任务script typetext/javascript new Promise((resolve , reject) { setTimeout(() { console.log(执行异步任务1); resolve(1) },1000) }).then( value { console.log(任务1的结果,value); console.log(执行同步任务2); return 2 } ).then( value { console.log(同步任务2的结果,value); return new Promise((resolve , reject) { //执行异步任务3 setTimeout(() { console.log(执行异步任务3); resolve(3) },1000) }) } ).then( value { console.log(异步任务3的结果); } ) /scriptpromise异常穿透当使用promise的then链式调用时可以在最后指定失败的回调前面任何操作出现异常都会传到最后失败的回调中处理script typetext/javascript new Promise((resolve , reject) { //resolve(1) reject(1) }).then( value { console.log(onResolve()1,value); return 2 }, //异常穿透相当于在每个then中 throw reason 或者 Promise.reject(reason) // reason { // throw reason // } // reason { // Promise.reject(reason) // } ).then( value { console.log(onResolve()2,value); return 3 } ).then( value { console.log(onResolve()3,value); } ).catch( reason { console.log(onRejected()1,reason); } ) /script中断promise链当使用promise的链式调用时在中间中断不再调用后面的回调函数办法在回调函数中返回一个pendding状态的promise对象script typetext/javascript new Promise((resolve , reject) { reject(1) }).then( value { console.log(onResolve()1,value); return 2 } ).then( value { console.log(onResolve()3,value); } ).catch( reason { console.log(onRejected()1,reason); return new Promise(() {})//返回一个pending的promise,中断promise链 } ).then( value { console.log(onResolve()4,value); }, reason { console.log(onRejected()2,reason); } ) /script三、自定义promise增加了resolveDelay和rejectDelay两个方法 助于理解promise原理实现函数版本/** * 自定义promise函数模块,使用ES5语法 */ //IIFE (function (window) { const PENDING pending const RESOLVED resolved const REJECTED rejected /** * Promise构造函数 * excutor:执行器函数(同步执行) */ function Promise (excutor) { //将当前promise对象保存起来 const self this self.status PENDING //给promise对象指定status初始值为pending self.data undefined // 给promise对象指定一个用于存储结果数据的属性 self.callbacks [] // 每个元素结构{ onResolved() {}, onRejected() {}} function resolve (value) { // 如果当前状态不是pending,直接结束 if (self.status ! PENDING) { return } //将状态改为resolved self.status RESOLVED //保存value数据 self.data value //如果有待执行的callbacks函数立即异步执行回调函数onResolved if (self.callbacks.length 0) { setTimeout(() { //放入队列中执行所有成功的回调 self.callbacks.forEach((callbacksObj) { callbacksObj.onResolved(value) }) }) } } function reject (reason) { // 如果当前状态不是pending,直接结束 if (self.status ! PENDING) { return } //将状态改为rejected self.status REJECTED //保存reason数据 self.data reason //如果有待执行的callbacks函数立即异步执行回调函数onRejected if (self.callbacks.length 0) { setTimeout(() { //放入队列中执行所有成功的回调 self.callbacks.forEach((callbacksObj) { callbacksObj.onRejected(reason) }) }) } } //立即同步执行excutor try { excutor(resolve , reject) }catch (error) { //如果执行器抛出异常promise对象变为rejected reject(error) } } //promise原型对象的then():指定成功和失败的回调函数返回一个新的promise对象 Promise.prototype.then function (onResolved , onRejected) { onResolved typeof onResolved function ? onResolved : value value //向后传递成功的value //指定默认的失败回调(实现错误/异常穿透的关键步骤) onRejected typeof onRejected function ? onRejected : reason { throw reason } //向后传递失败的reason const self this //返回一个新的promise对象 return new Promise((resolve , reject) { //调用指定的回调函数处理根据执行的结果改变return的promise状态 function handle (callback) { try { const result callback(self.data) if (result instanceof Promise) { /*如果回调函数返回promisereturn的promise结果就是这个promise的结果*/ // result.then( // value resolve(value), //当result成功时让return的promise也成功 // reason reject(reason) //当result失败时让return的promise也失败 // ) //简洁写法 result.then(resolve , reject) } else { /*如果回调函数返回的不是promisereturn的promise就会成功value就是返回的值*/ resolve(result) } } catch (error) { reject(error) } } if (self.status PENDING) { //当前状态是pending状态,将回调函数保存起来 self.callbacks.push({ onResolved () { handle(onResolved) }, onRejected () { handle(onRejected) } }) } else if (self.status RESOLVED) { //如果当前是resolved状态异步执行onResolved并改变return的promise状态 setTimeout(() { handle(onResolved) }) } else { //如果当前是rejected状态异步执行onRejected并改变return的promise状态 setTimeout(() { handle(onRejected) }) } }) } //promise原型对象的catch()指定失败的回调函数返回一个新的promise Promise.prototype.catch function (onRejected) { return this.then(undefined , onRejected) } /** * Promise函数方法 * resolve返回一个指定结果的成功的promise * reject返回一个指定的reason的失败的promise * all返回一个promise只有当所有promise都成功时才算成功否则失败 * race返回一个promise其结果由第一个完成的promise决定 */ Promise.resolve function (value) { //返回一个成功/失败的promise return new Promise((resolve , reject) { // value是promise if (value instanceof Promise) { //使用value的结果作为当前promise结果 value.then(resolve , reject) } else { // value不是promise resolve(value) } }) } Promise.reject function (reason) { // 返回一个失败的promise return new Promise((resolve , reject) { reject(reason) }) } Promise.all function (promises) { //用来保存 所有成功value的数组 const values new Array(promises.length) //用来保存成功promise的数量 let resolveCount 0 //返回一个新的promise return new Promise((resolve , reject) { //遍历获取每个promise结果 promises.forEach((p , index) { Promise.resolve(p).then( value { resolveCount //p成功将成功的value保存到values中 values[index] value //如果全部成功将return的promise改为成功 if (resolveCount promises.length) { resolve(values) } }, reason { //只要有一个失败了所有都失败 reject(reason) } ) }) }) } Promise.race function (promises) { //返回一个新的promise return new Promise((resolve, reject) { //遍历获取每个promise结果 promises.forEach((p , index) { Promise.resolve(p).then( value { //一旦有成功的将return变为成功 resolve(value) }, reason { //只要有一个失败了所有都失败 reject(reason) } ) }) }) } /** * 返回一个promise对象在指定的时间后确定结果 */ Promise.resolveDelay function (value, time) { //返回一个成功/失败的promise return new Promise((resolve , reject) { setTimeout(() { // value是promise if (value instanceof Promise) { //使用value的结果作为当前promise结果 value.then(resolve , reject) } else { // value不是promise resolve(value) } },time) }) } /** * 返回一个promise对象在指定的时间之后失败 */ Promise.rejectDelay function (reason, time) { // 返回一个失败的promise return new Promise((resolve , reject) { setTimeout(() { reject(reason) }) }) } //向外暴露promise函数 window.Promise Promise })(window)class版本/** * 自定义promise函数模块,使用ES5语法 */ //IIFE (function (window) { const PENDING pending const RESOLVED resolved const REJECTED rejected class Promise { constructor (excutor) { //将当前promise对象保存起来 const self this self.status PENDING //给promise对象指定status初始值为pending self.data undefined // 给promise对象指定一个用于存储结果数据的属性 self.callbacks [] // 每个元素结构{ onResolved() {}, onRejected() {}} function resolve (value) { // 如果当前状态不是pending,直接结束 if (self.status ! PENDING) { return } //将状态改为resolved self.status RESOLVED //保存value数据 self.data value //如果有待执行的callbacks函数立即异步执行回调函数onResolved if (self.callbacks.length 0) { setTimeout(() { //放入队列中执行所有成功的回调 self.callbacks.forEach((callbacksObj) { callbacksObj.onResolved(value) }) }) } } function reject (reason) { // 如果当前状态不是pending,直接结束 if (self.status ! PENDING) { return } //将状态改为rejected self.status REJECTED //保存reason数据 self.data reason //如果有待执行的callbacks函数立即异步执行回调函数onRejected if (self.callbacks.length 0) { setTimeout(() { //放入队列中执行所有成功的回调 self.callbacks.forEach((callbacksObj) { callbacksObj.onRejected(reason) }) }) } } //立即同步执行excutor try { excutor(resolve , reject) }catch (error) { //如果执行器抛出异常promise对象变为rejected reject(error) } } //promise原型对象的then():指定成功和失败的回调函数返回一个新的promise对象 then (onResolved , onRejected) { onResolved typeof onResolved function ? onResolved : value value //向后传递成功的value //指定默认的失败回调(实现错误/异常穿透的关键步骤) onRejected typeof onRejected function ? onRejected : reason { throw reason } //向后传递失败的reason const self this //返回一个新的promise对象 return new Promise((resolve , reject) { //调用指定的回调函数处理根据执行的结果改变return的promise状态 function handle (callback) { try { const result callback(self.data) if (result instanceof Promise) { /*如果回调函数返回promisereturn的promise结果就是这个promise的结果*/ // result.then( // value resolve(value), //当result成功时让return的promise也成功 // reason reject(reason) //当result失败时让return的promise也失败 // ) //简洁写法 result.then(resolve , reject) } else { /*如果回调函数返回的不是promisereturn的promise就会成功value就是返回的值*/ resolve(result) } } catch (error) { reject(error) } } if (self.status PENDING) { //当前状态是pending状态,将回调函数保存起来 self.callbacks.push({ onResolved () { handle(onResolved) }, onRejected () { handle(onRejected) } }) } else if (self.status RESOLVED) { //如果当前是resolved状态异步执行onResolved并改变return的promise状态 setTimeout(() { handle(onResolved) }) } else { //如果当前是rejected状态异步执行onRejected并改变return的promise状态 setTimeout(() { handle(onRejected) }) } }) } //promise原型对象的catch()指定失败的回调函数返回一个新的promise catch (onRejected) { return this.then(undefined , onRejected) } /** * Promise函数方法 * resolve返回一个指定结果的成功的promise * reject返回一个指定的reason的失败的promise * all返回一个promise只有当所有promise都成功时才算成功否则失败 * race返回一个promise其结果由第一个完成的promise决定 */ static resolve function (value) { //返回一个成功/失败的promise return new Promise((resolve , reject) { // value是promise if (value instanceof Promise) { //使用value的结果作为当前promise结果 value.then(resolve , reject) } else { // value不是promise resolve(value) } }) } static reject function (reason) { // 返回一个失败的promise return new Promise((resolve , reject) { reject(reason) }) } static all function (promises) { //用来保存 所有成功value的数组 const values new Array(promises.length) //用来保存成功promise的数量 let resolveCount 0 //返回一个新的promise return new Promise((resolve , reject) { //遍历获取每个promise结果 promises.forEach((p , index) { Promise.resolve(p).then( value { resolveCount //p成功将成功的value保存到values中 values[index] value //如果全部成功将return的promise改为成功 if (resolveCount promises.length) { resolve(values) } }, reason { //只要有一个失败了所有都失败 reject(reason) } ) }) }) } static race function (promises) { //返回一个新的promise return new Promise((resolve, reject) { //遍历获取每个promise结果 promises.forEach((p , index) { Promise.resolve(p).then( value { //一旦有成功的将return变为成功 resolve(value) }, reason { //只要有一个失败了所有都失败 reject(reason) } ) }) }) } /** * 返回一个promise对象在指定的时间后确定结果 */ static resolveDelay function (value, time) { //返回一个成功/失败的promise return new Promise((resolve , reject) { setTimeout(() { // value是promise if (value instanceof Promise) { //使用value的结果作为当前promise结果 value.then(resolve , reject) } else { // value不是promise resolve(value) } },time) }) } /** * 返回一个promise对象在指定的时间之后失败 */ static rejectDelay function (reason, time) { // 返回一个失败的promise return new Promise((resolve , reject) { setTimeout(() { reject(reason) }) }) } } //向外暴露promise函数 window.Promise Promise })(window)四、 如何按顺序执行多个Promise如 promise如何串联多个操作任务问题背景假设我们有以下三个异步操作的函数operation1()、operation2()和operation3()它们分别返回一个Promise对象。我们希望按照顺序先执行operation1()然后是operation2()最后执行operation3()。function operation1() { return new Promise((resolve, reject) { // 这里是异步操作的逻辑 }); } function operation2() { return new Promise((resolve, reject) { // 这里是异步操作的逻辑 }); } function operation3() { return new Promise((resolve, reject) { // 这里是异步操作的逻辑 }); }解决方案示例//假设我们有一个需要登录和加载用户信息的应用程序。我们需要按照以下顺序执行三个异步操作验证用户凭据、获取用户信息、加载用户页面。 function verifyCredentials(username, password) { return new Promise((resolve, reject) { // 模拟异步操作验证用户凭据 setTimeout(() { if (username admin password 123456) { resolve(); } else { reject(用户名或密码错误); } }, 1000); }); } function getUserInfo() { return new Promise((resolve, reject) { // 模拟异步操作获取用户信息 setTimeout(() { resolve({ username: admin, email: adminexample.com }); }, 1500); }); } function loadUserPage() { return new Promise((resolve, reject) { // 模拟异步操作加载用户页面 setTimeout(() { resolve(); }, 2000); }); }方法一使用.then()链式调用第一种解决方法是使用Promise对象的.then()方法来逐个调用这些函数并将它们串联在一起。代码如下operation1() .then(() { return operation2(); }) .then(() { return operation3(); }) .then(() { // 所有操作完成后的逻辑 });verifyCredentials(admin, 123456) .then(() { return getUserInfo(); }) .then(() { return loadUserPage(); }) .then(() { console.log(用户页面加载完成); }) .catch((error) { console.error(出错了 error); });这种方法适用于操作之间没有依赖关系的情况下。每个.then()都会返回一个新的Promise对象使得我们能够在前一个操作完成后执行下一个操作。方法二使用async/await第二种解决方法是使用ES6中的async/await语法糖。async/await提供了一种更简洁的方式来处理异步操作的流程。代码如下async function execute() { await operation1(); await operation2(); await operation3(); // 所有操作完成后的逻辑 } execute();async function execute() { try { await verifyCredentials(admin, 123456); await getUserInfo(); await loadUserPage(); console.log(用户页面加载完成); } catch (error) { console.error(出错了 error); } } execute();async函数会返回一个Promise对象其中的await关键字会等待Promise的解析结果。这样我们就可以按照顺序执行异步操作并在每个操作完成后等待下一个操作。方法三使用Promise.all()第三种解决方法是使用Promise.all()方法来同时执行多个Promise并等待它们全部完成。代码如下Promise.all([operation1(), operation2(), operation3()]) .then(() { // 所有操作完成后的逻辑 });Promise.all([verifyCredentials(admin, 123456), getUserInfo(), loadUserPage()]) .then(() { console.log(用户页面加载完成); }) .catch((error) { console.error(出错了 error); });Promise.all()方法接受一个Promise对象数组作为参数并返回一个新的Promise对象。这个新的Promise对象在所有传入的Promise对象都解析时解析并将它们的结果以数组的形式传递给.then()方法。总结通过以上三种方法我们可以按顺序执行多个Promise并控制它们的流程。使用链式调用的.then()方法、async/await语法和Promise.all()方法是实现这一目标的常用方案。在选择使用哪种方法时可以根据实际情况进行判断。如果操作之间没有依赖关系可以使用链式调用如果需要依次执行并等待每个操作完成可以使用async/await如果需要同时执行多个操作并等待它们全部完成可以使用Promise.all()。五、不定数目的Promise的串行调用Promise数量都是固定的调用起来非常方便当然对于Promise.all方式调用可以调用任意个数量的Promise只要传进来的参数是个数组就可以。但是对于串行调用即p1().then(p2).then(p3).then((result) {})的形式如果Promise数量不是固定的就无法通过枚举的形式一个一个列出来加到then中进行调用。此时我们可以借助于Array.reduce()进行串行调用Array.reduce()方法通常用于数组的累加求和const arr []; const p1 () { return new Promise((resolve, reject) { setTimeout(() { console.log(new Date()); resolve(); }, 1000) }) } arr.push(p1); const p2 () { return new Promise((resolve, reject) { setTimeout(() { console.log(new Date()); resolve(); // resolve(); }, 1000) }) } arr.push(p2); const p3 () { return new Promise((resolve, reject) { setTimeout(() { console.log(new Date()); resolve(); }, 1000) }) } arr.push(p3); // 可以在数组arr中添加其他Promise... arr.reduce((prev, curv) { return prev.then(() { return curv().then() }) }, Promise.resolve()).then(() { console.log(all resolved); }).catch(err { console.log(error); console.error(err); });其他方案function delay(time) { return new Promise((resolve, reject) { console.log(wait ${time}s) setTimeout(() { console.log(execute); resolve() }, time * 1000) }) } const arr [3, 4, 5]; // 一个封装的延迟函数然后一个装有3,4,5的数组需求就是在开始执行时依次等待3, 4, 5秒并在之后打印对应输出 wait 3s // 等待3s execute wait 4s // 等待4s execute wait 5s // 等待5s execute方式1. reduce:比较简单和常见的方式( async function () { for (const v of arr) { await delay(v) } } )()方式2. async 循环 await( async function () { for (const v of arr) { await delay(v) } } )() //本质上使用了async/await的功能方式3. 普通循环其实仔细想想方式1的本质是使用一个中间变量上一次执行结果来保存链式Promise, 那我们举一反三 换别的循环也可以实现let p Promise.resolve() for (const i of arr) { p p.then(() delay(i)) } //理论上所有循环方式都能实现只要找到一个保存链式Promise的地方闭包也好参数也好。 //其实使用while循环时遇到一些坑例如这样写。 let i let p Promise.resolve() while (i arr.shift()) { p p.then(() delay(i)) } //思路没啥问题问题就在于i放在外层时实际上每次都被改动这和一道经典的面试题一样 for(var i 0, i 5, i) { setTimeout(() { console.log(i) }, i * 1000) } //事实上他们都会输出5。所以对于while循环我们需要在内部也保存一份最后我改成这样感觉有点蠢不过也没想到其他办法 let i let p Promise.resolve() while (i arr.shift()) { let s i p p.then(() delay(s)) }方式4. 递归这是面试官提供的思路也提到了koa其实koa自己也有研究其中洋葱模型来自于koa-compose库。function dispatch(i, p Promise.resolve()) { if (!arr[i]) return Promise.resolve() return p.then(() dispatch(i 1, delay(arr[i]))) } dispatch(0)方式5. for await of通过查阅了for await of的规则其实for await of和for of规则类似只需要实现一个内部[Symbol.asyncIterator]方法即可function createAsyncIterable(arr) { return { [Symbol.asyncIterator]() { return { i: 0, next() { if (this.i arr.length) { return delay(arr[this.i]).then(() ({ value: this.i, done: false })); } return Promise.resolve({ done: true }); } }; } } } (async function () { for await (i of createAsyncIterable(arr)) { } })(); //先创建出一个可异步迭代对象然后丢到for await of循环即可方式6. generatorfunction* gen() { for (const v of arr) { yield delay(v) } } function run(gen) { const g gen() function next(data) { const result g.next(data) if (result.done) return result.value result.value.then(function(data) { next(data) }) } next() } run(gen) //先创建一个generator函数然后再封装一个自执行run函数六、JS异步之宏队列和微队列说明JS中用来存储待执行回调函数的队列包含两个不同特定的队列宏队列用来保存待执行的宏任务(回调),比如定时器回调/DOM事件回调/Ajax回调微队列用来保存待执行的微任务(回调)比如promise的回调/mutationObserver()的回调JS执行时会区别这两个队列JS引擎首先必须执行所有的初始化同步代码每次准备取出第一个宏任务执行前都要将所有的微任务一个一个取出来执行