先上代码

公共代码

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}毫秒`);
}

输出

["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',
第一种方法很好理解,就是一步一步执行,这种方法适合请求参数依赖上一个请求返回值的情况,在这里是不存在这种关系的,也就是这种方法在这里效率是比较低的。

第二种方法一开始就发起了3个请求,并等待3请求都到达后获取数据。

第三种方法也一开始就发起了3个请求,并在请求到达后依次执行,因为a请求到达时间是2秒,a请求到达后,把a的结果推入results,再往下执行,b请求是3秒,b请求迟a请求一秒到达,也就是再过一秒后把b的结果推入results,,c的请求是1秒,这个时候c早已到达,在这轮循环末尾可以立即把c推入。a请求返回的数据2秒后就能操作了,这种方法比第二种方法可以更快处理数据。如果请求时间是依次递减的,那么和方法二效果是一样,在有多个请求时这种情况一般不存在。

第四种方法和第三种方法的区别是最先到达的请求最快放入结果集,也就是我不用排队等待处理,哪个数据先返回我就先处理哪个数据,假如c请求返回的数据需要花比较长的时间处理,我在一秒后就能开始处理了,但是第三种方法我得3秒后才能开始处理。可以看到我把results的输出放在了b请求到达的函数中,因为results在最后一个请求到达后才能完整输出,与方法三的区别是获取结果的操作也是异步的,这个很关键,也是和方法三最大的区别,通过在外层包装一个自执行函数,可以防止await的操作权跳出laucher外部,从而并发发起3个获取结果的操作。可能大家会有疑问假如我不清楚哪个请求最后到达,那怎么获取最后的results值,这种情况可以在外面包一个Promise.all,可以仔细看一下下面两个函数的区别

  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"] "输出时间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);

async/await 真不是你想象中那么简单的更多相关文章

  1. show()封装没有想象中那么简单

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. 食之无味?App Startup 可能比你想象中要简单

    请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ...

  3. 刚刚完成了在vs2013中通过 ef连接mysql数据库的工作。感觉没有想象中的简单。试了n次终于成功。故记录成功的方法,希望可以帮到大家

    分两种情况,如果你是用entity framework 5.0的时候 mysql-connector-net的版本不是很重要. MySQL For VisualStudio的版本也不重要 (这个不装就 ...

  4. 【TypeScript】如何在TypeScript中使用async/await,让你的代码更像C#。

    [TypeScript]如何在TypeScript中使用async/await,让你的代码更像C#. async/await 提到这个东西,大家应该都很熟悉.最出名的可能就是C#中的,但也有其它语言也 ...

  5. [译]async/await中阻塞死锁

    这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Cleary的两篇博文中翻译过来. 原文1:Don'tBlock o ...

  6. C# async/await 使用总结

    今天搞这两个关键字搞得有点晕,主要还是没有彻底理解其中的原理. 混淆了一个调用异步方法的概念: 在调用异步方法时,虽然方法返回一个 Task,但是其中的代码已经开始执行.该方法在调用时,即刻执行了一部 ...

  7. C# 异步操作 async await

    在编程的过程中,我们会遇到很多需要异步操作的场景.比如要下载一个文件,如果使用同步的方式进行下载,那么UI操作就会被卡住,这时最好能够使用异步的方式进行下载.在C#中,很早就开始支持异步的操作了,只不 ...

  8. Async/Await替代Promise的6个理由

    译者按: Node.js的异步编程方式有效提高了应用性能:然而回调地狱却让人望而生畏,Promise让我们告别回调函数,写出更优雅的异步代码:在实践过程中,却发现Promise并不完美:技术进步是无止 ...

  9. 浅谈Async/Await

    概要 在很长一段时间里面,FE们不得不依靠回调来处理异步代码.使用回调的结果是,代码变得很纠结,不便于理解与维护,值得庆幸的是Promise带来了.then(),让代码变得井然有序,便于管理.于是我们 ...

随机推荐

  1. 编译LAMP部署动态网站环境

    LAMP动态网站部署架构是由一套 Linux+Apache+MySQL+PHP 组成的动态网站系统解决方案. 以下配置环境为:Linux=RHEL7 --> Apache=2.4.33 --&g ...

  2. innodb中一颗B+树能存储多少条数据

    如图,为B+树组织数据的方式: 实际存储时当然不会每个节点只存3条数据. 以InnoDB引擎为例,简单计算一下一颗B+树可以存放多少行数据. B+树特点:只有叶子节点存储数据,而非叶子节点存放的是用来 ...

  3. RBAC(基于角色的访问控制)用户权限管理数据库设计

    RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成“用户-角色- ...

  4. HTTP/HTTPS协议 & GraphQL(非RESTFUL方式)

    HTTP访问控制-跨域资源共享(CORS) 缓存管理 HTTP VS HTTPS架构 TLS协议 HTTPS会话劫持 基于HTTP协议的服务器消息机制 1. Longpoll 2. SSE 3. We ...

  5. wampserver2.2 在window2003下的安装的主要问题

    准备安装最新的wampserver 2.2c,   1.安装问题,安装完成后总是无法启动服务   系统事件中提示错误 找不到附属汇编 Microsoft.VC90.CRT,上一个错误是 参照的汇编没有 ...

  6. Qt Creator 4.10 Beta版发布

    使用Qt Creator 4.10 Beta,现在支持固定文件,因此即使在关闭所有文件时它们仍然保持打开状态,围绕语言服务器协议支持继续集成,将Android目标添加到CMake/Qbs项目,支持Bo ...

  7. CDN和浏览器缓存

    1,CDN 旨在解决的最重要的问题是什么,我们称之为网络延迟,通过网络获取资源总是比从本地获取慢,无论服务器是在同一个局域网中还是位于世界的另一个角落,都是如此.这里的速度差异是 IT 行业的一个核心 ...

  8. Stopwatch简单时间检测

    public ActionResult Index() { Stopwatch sw = new Stopwatch(); //实例化一个对象 sw.Start(); //开始计算 int[] a = ...

  9. l洛谷P4779 【模板】单源最短路径(标准版)(dijkstra)

    题目描述 给定一个 NN 个点,MM 条有向边的带非负权图,请你计算从 SS 出发,到每个点的距离. 数据保证你能从 SS 出发到任意点. 输入格式 第一行为三个正整数 N, M, SN,M,S. 第 ...

  10. 二分答案 + multiset || NOIP 2018 D1 T3 || Luogu P5021 赛道修建

    题面:P5021 赛道修建 题解:二分答案,用Dfs进行判断,multiset维护. Dfs(x,fa,Lim)用来计算以x为根的子树中有多少符合条件的路径,并返回剩余未使用的最长路径长. 贪心思想很 ...