先上代码promise
function getData(data, time) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(data); }, time) }) } let results = []; let startTime = new Date(); laucher();
async function laucher() { let dataA = await getData('a', 2000); results.push(`${dataA}在${new Date() - startTime}毫秒放入`); let dataB = await getData('b', 3000); results.push(`${dataB}在${new Date() - startTime}毫秒放入`); let dataC = await getData('c', 1000); results.push(`${dataC}在${new Date() - startTime}毫秒放入`); console.log(results, `输出时间${new Date() - startTime}毫秒`); }
输出并发
["a在2002毫秒放入", "b在5004毫秒放入", "c在6006毫秒放入"] "输出时间6006毫秒"
async function laucher() { let dataAPromise = getData('a', 2000); let dataBPromise = getData('b', 3000); let dataCPromise = getData('c', 1000); let promises = [dataAPromise, dataBPromise, dataCPromise]; results = await Promise.all(promises); console.log(results, `输出时间${new Date() - startTime}毫秒`); }
输出异步
["a", "b", "c"] "输出时间3006毫秒"
async function laucher() { let dataAPromise = getData('a', 2000); let dataBPromise = getData('b', 3000); let dataCPromise = getData('c', 1000); dataA = await dataAPromise; results.push(`${dataA}在${new Date() - startTime}毫秒放入`); dataB = await dataBPromise; results.push(`${dataB}在${new Date() - startTime}毫秒放入`); dataC = await dataCPromise; results.push(`${dataC}在${new Date() - startTime}毫秒放入`); console.log(results, `输出时间${new Date() - startTime}毫秒`); }
输出async
["a在2003毫秒放入", "b在3001毫秒放入", "c在3001毫秒放入"] "输出时间3002毫秒"
async function laucher() { let dataAPromise = getData('a', 2000); let dataBPromise = getData('b', 3000); let dataCPromise = getData('c', 1000); (async () => { dataA = await dataAPromise; results.push(`${dataA}在${new Date() - startTime}毫秒放入`); })(); (async () => { dataB = await dataBPromise; results.push(`${dataB}在${new Date() - startTime}毫秒放入`); console.log(results, `输出时间${new Date() - startTime}毫秒`);//results放在最后返回的请求中 })(); (async () => { dataC = await dataCPromise; results.push(`${dataC}在${new Date() - startTime}毫秒放入`); })(); }
输出函数
["c在1002毫秒放入", "a在2002毫秒放入", "b在3003毫秒放入"] "输出时间3003毫秒"
使用setTimeout模拟了3条异步请求,分别2000,3000,1000毫秒后返回'a', 'b', 'c',
第一种方法很好理解,就是一步一步执行,这种方法适合请求参数依赖上一个请求返回值的状况,在这里是不存在这种关系的,也就是这种方法在这里效率是比较低的。code
第二种方法一开始就发起了3个请求,并等待3请求都到达后获取数据。get
第三种方法也一开始就发起了3个请求,并在请求到达后依次执行,由于a请求到达时间是2秒,a请求到达后,把a的结果推入results,再往下执行,b请求是3秒,b请求迟a请求一秒到达,也就是再过一秒后把b的结果推入results,,c的请求是1秒,这个时候c早已到达,在这轮循环末尾能够当即把c推入。a请求返回的数据2秒后就能操做了,这种方法比第二种方法能够更快处理数据。若是请求时间是依次递减的,那么和方法二效果是同样,在有多个请求时这种状况通常不存在。it
第四种方法和第三种方法的区别是最早到达的请求最快放入结果集,也就是我不用排队等待处理,哪一个数据先返回我就先处理哪一个数据,假如c请求返回的数据须要花比较长的时间处理,我在一秒后就能开始处理了,可是第三种方法我得3秒后才能开始处理。能够看到我把results的输出放在了b请求到达的函数中,由于results在最后一个请求到达后才能完整输出,与方法三的区别是获取结果的操做也是异步的,这个很关键,也是和方法三最大的区别,经过在外层包装一个自执行函数,能够防止await的操做权跳出laucher外部,从而并发发起3个获取结果的操做。可能你们会有疑问假如我不清楚哪一个请求最后到达,那怎么获取最后的results值,这种状况能够在外面包一个Promise.all,能够仔细看一下下面两个函数的区别io
async function laucher() { let dataAPromise = getData('a', 2000); let dataBPromise = getData('b', 3000); let dataCPromise = getData('c', 1000); let promises = [dataAPromise, dataBPromise, dataCPromise]; results = await Promise.all(promises); console.log(results, `输出时间${new Date() - startTime}毫秒`); }
输出console
["a", "b", "c"] "输出时间3003毫秒"
async function laucher() { let dataAPromise = getData('a', 2000); let dataBPromise = getData('b', 3000); let dataCPromise = getData('c', 1000); let promises = [dataAPromise, dataBPromise, dataCPromise]; results = await Promise.all(promises.map(async function (promise) { let data = await promise; console.log(`${data}在${new Date() - startTime}毫秒输出`); //这里能够提早处理数据 return data })); console.log(results); }
输出
c在1002毫秒输出 a在2003毫秒输出 b在3003毫秒输出 ["a", "b", "c"] "输出时间3004毫秒"
若是请求之间不存在继发关系,而且请求到达后要执行一些运算,那么按效率来讲
方法4 > 方法3 > 方法2 > 方法1
每种方法都对应一种加载的策略,以一个使用场景来讲明一下,向后台加载页面组件(假设组件个数是3)
执行流程:
方法一: 发起组件1的请求 -> 组件1数据到达后渲染组件1 -> 发起组件2的请求 -> 组件2数据到达后渲染组件2 -> 发起组件3的请求 -> 组件3数据到达后渲染组件3
方法二: 同时发起组件1,2,3的请求 -> 组件1,2,3的数据都到达后渲染组件1,2,3
方法三: 同时发起组件1,2,3的请求 -> 组件1数据到达后渲染组件1 -> 组件2数据到达后渲染组件2 -> 组件3数据到达后渲染组件3
方法四: 同时发起组件1,2,3的请求 -> 最快到达的组件数据到达后渲染最快到达的组件 -> 第二快到达的组件数据到达后渲染第二快到达的组件 -> 最慢到达的组件数据到达后渲染最慢到达的组件
针对以上场景能够看出方法四可让咱们的页面最快渲染出内容
能够看出虽然引入async/await,可让你的代码很精简,可是async/await自己的执行流程倒是很复杂的,下面的代码你能够猜一下输出结果(补充一点:有的文章会指出forEach函数不能放入异步操做,这种结论是错误的,若是是继发关系确实不适宜用forEach,但不能表示不能放入异步操做,反而这种操做能提升获取数据的效率)
[1, 2].forEach(async function (value) { console.log(value); await console.log('a'); console.log('c'); await console.log('d'); console.log('e'); }) console.log(3);