摘要:对于而言,异步编程我们可以采用回调函数,事件监听,发布订阅等方案,在之后,又新添了,,的方案。总结本文阐述了从回调函数到的演变历史。参考文档深入掌握异步编程系列理解的
对于JS而言,异步编程我们可以采用回调函数,事件监听,发布订阅等方案,在ES6之后,又新添了Promise,Genertor,Async/Await的方案。本文将阐述从回调函数到Async/Await的演变历史,以及它们之间的关系。1. 异步编程的演变
首先假设要渲染一个页面,只能异步的串行请求A,B,C,然后才能拿到页面的数据并请求页面
针对于不同的异步编程方式,我们会得到如下的代码:
1.1 回调函数// 假设request是一个异步函数 request(A, function () { request(B, function () { request(C, function () { // 渲染页面 }) }) })
回调函数的嵌套是愈发深入的。在不断的回调中,request(A)回调函数中的其他逻辑会影响到request(B),request(C)中的逻辑,同理,request(B)中的其他逻辑也会影响到request(C)。在这个例子中,request(A)调用request(B),request(B)调用request(C),request(C)执行完毕返回,request(B)执行完毕返回,request(A)执行完毕返回。我们很快会对先后顺序产生混乱,从而很难直观的分析出异步回调的结果。这就被称为回调地狱。
为了解决这种情况,ES6新增了Promise对象。
1.2 Promise// 假设request是一个Promise函数 request(A).then(function () { return request(B) }).then(function () { return request(C) }).then(function () { // 渲染页面 })
Promise对象用then函数来指定回调。所以,之前在1.1中回调函数的例子可以改为上文中的模样。可以看到,Promise并没有消除回调地狱,但是却通过then链将代码逻辑变得更加清晰了。在这个例子中,request(A)调用request(B),request(B)调用request(C),request(C)执行完毕返回。现在,request(A)中的内容只能通过显示声明的data来影响到request(C)——如果没有显示的在回调中声明,则影响不了request(C),换言之,每段回调被近乎独立的分割了。
但是Promise本身还是有一堆的then,还是不能让我们像写同步代码一样写异步的代码,因此JS又引入了Generator。
1.3 Generatorfunction* gen(){ var r1 = yield request(A) var r2 = yield request(B) var r3 = yield request(C) // 渲染页面 };
Generator是协程在ES6上的实现,协程是指一个线程上不同函数间执行权可以相互切换。如本例,先执行gen(),然后在遇到yield时暂停,执行权交给request(A),等到调用了next()方法,再将执行权还给gen()。
通过协程,JS就实现了用同步的方式写异步的代码,但是Generator的使用要配合执行器,这自然是麻烦的。于是就有了Async/Await。
Generator的自动执行器是co函数库,有兴趣的同学可以通过阅读《co 函数库的含义和用法》来进行了解。1.4 Async/Await
async function gen() { var r1 = await request(A) var r2 = await request(B) var r3 = await request(C) // 渲染页面 }
如果比较代码的话,1.4的代码只是把1.3的代码中* => async,yield变为await。但Async函数的实现,就是将 Generator函数和自动执行器,包装在一个函数里[1]。spawn就是自动执行器。
async function fn(args){ // ... } // 等同于 function fn(args){ return spawn(function*() { // ... }); }
除此以外,Async函数比Generator函数有更好的延展性——yield接的是Promise函数/Thunk函数,但await还可以包括普通函数。对于普通函数,await表达式的运算结果就是它等到的东西。否则若await等到的是一个Promise函数,await就会协程到这个Promise函数上,直到它resolve或者reject,然后再协程回主函数上[2]。当然,Async函数也比Generator函数更加易读和易理解。
2. 总结本文阐述了从回调函数到Async/Await的演变历史。Async函数作为换一个终极解决方案,尽管在并行异步处理上还要借助Promise.all(),但其他方面已经足够完美。
参考文档《深入掌握 ECMAScript 6 异步编程》系列
《理解JavaScript的 async/await》
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/108887.html
摘要:三即生成器,它是生成器函数返回的一个对象,是中提供的一种异步编程解决方案而生成器函数有两个特征,一是函数名前带星号,二是内部执行语句前有关键字调用一个生成器函数并不会马上执行它里面的语句,而是返回一个这个生成器的迭代器对象。 文章来自微信公众号:前端工坊(fe_workshop),不定期更新有趣、好玩的前端相关原创技术文章。 如果喜欢,请关注公众号:前端工坊版权归微信公众号所有,转载请...
摘要:的翻译文档由的维护很多人说,阮老师已经有一本关于的书了入门,觉得看看这本书就足够了。前端的异步解决方案之和异步编程模式在前端开发过程中,显得越来越重要。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。 JavaScript Promise 迷你书(中文版) 超详细介绍promise的gitbook,看完再不会promise...... 本书的目的是以目前还在制定中的ECMASc...
摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。异步编程入门的全称是前端经典面试题从输入到页面加载发生了什么这是一篇开发的科普类文章,涉及到优化等多个方面。 TypeScript 入门教程 从 JavaScript 程序员的角度总结思考,循序渐进的理解 TypeScript。 网络基础知识之 HTTP 协议 详细介绍 HTT...
摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。写一个符合规范并可配合使用的写一个符合规范并可配合使用的理解的工作原理采用回调函数来处理异步编程。 JavaScript怎么使用循环代替(异步)递归 问题描述 在开发过程中,遇到一个需求:在系统初始化时通过http获取一个第三方服务器端的列表,第三方服务器提供了一个接口,可通过...
阅读 1431·2021-11-19 09:55
阅读 2736·2021-09-06 15:02
阅读 3458·2019-08-30 15:53
阅读 912·2019-08-29 16:36
阅读 1174·2019-08-29 16:29
阅读 2206·2019-08-29 15:21
阅读 578·2019-08-29 13:45
阅读 2651·2019-08-26 17:15