说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

细说JavaScript异步函数发展历程

HTML文档下载 WORD文档下载 PDF文档下载
对大部分JavaScript开发者而言,async函数仍是新鲜事物,其发展经历了漫长的旅程。本文将梳理总结JavaScript异步函数的发展历程,并表示未来async函数将成为实现异步的主要方式。

《The Evolution of Asynchronous JavaScript》外文梳理了JavaScript异步函数的发展历程,首先通过回调函数实现异步,之后又经历了Promise/A+、生成器函数,而未来将是async函数的。感谢景庄对该文章的翻译,内容如下:

对大部分的JavaScript开发者而言,async函数是个新鲜事物,它的发展经历了一个漫长的旅程。因此本文试图梳理总结JavaScript异步函数的发展历程:在不久之前,我们还只能写回调函数来实现异步,然后Promise/A+标准出来了,这之后又出现了生成器函数,而未来显然是async函数的。

现在让我们一起来回顾这些年来JavaScript异步函数的发展历程吧。

回调函数Callbacks

似乎一切应该从回调函数开始谈起。

异步JavaScript

正如我们所知道的那样,在JavaScript中,异步编程方式只能通过JavaScript语言中的一等公民函数才能完成:这种方式意味着我们可以将一个函数作为另一个函数的参数,在这个函数的内部可以调用被传递进来的函数(即回调函数)。这也正是回调函数诞生的原因:如果你将一个函数作为参数传递给另一个函数(此时它被称为高阶函数),那么在函数内部, 你可以调用这个函数来完成相应的任务。回调函数没有返回值(不要试图用return),仅仅被用来在函数内部执行某些动作。 看一个例子:

Something.save(function(err) {    if (err)  {    //error handling    return; // 没有返回值  }  console.log('success');});

上面的例子中我们演示了一个错误优先的回调函数(error-first callbacks),这也是Node.js本身的特点之一, Node.js中所有的核心模块和NPM仓库中的大部分模块在编写时都会遵循这个特点。

过度使用回调函数所会遇到的挑战:

  • 如果不能合理的组织代码,非常容易造成回调地狱(callback hell),这会使得你的代码很难被别人所理解。
  • 很容易遗漏错误处理代码。
  • 无法使用return语句返回值,并且也不能使用throw关键字。

也正是基于这些原因,在JavaScript世界中,一直都在寻找着能够让异步JavaScript开发变得更简单的可行的方案。

一个可行的解决方案之一是async模块。如果你和回调函数打过很久的交道, 你也许会深刻地感受到,在JavaScript中如果想要让某些事并行执行,或是串行执行,甚至是使用异步函数来映射(mapping) 数组中的元素使用异步函数有多复杂。所以,感谢 Caolan McMahon写了async模块来解决这些问题。

使用async模块,你可以轻松地以下面这种方式编写代码:

async.map([1, 2, 3], AsyncSquaringLibrary.square,    function(err, result){  // result will be [1, 4, 9]});

async模块虽然一定程度上带来了便利,但仍然不够简单,代码也不容易阅读,因此Promise出现了。

Promise

当前的JavaScript异步标准可以追溯到2012年,并且直到ES6才变得可用,然而,Promise这个术语却并不是JavaScript 社区所发明的。这个术语来来自于 Daniel P.friedman在1976年的发表的一篇文章。

一个Promise代表的是一个异步操作的最终结果。

现在我们使用Promise来完成上面代码所完成的任务,Promise风格的代码如下:

Something.save()    .then(function() {    console.log('success');  })  .catch(function() {    //error handling  })

你会发现,Promise中也利用了回调函数。在then和catch方法中都传入了一个回调函数,分别在Promise被满足和被拒绝时执行。Promise函数的另一个优点是它能够被链接起来完成一系列任务。例如,你可以这样写代码:

saveSomething()    .then(updateOtherthing)  .then(deleteStuff)    .then(logResults);

当你没有现成的Promise时,你可能需要借助一些Promise库,一个流行的选择是使用 bluebird。 这些库可能会提供比原生方案更多的功能,并且不局限于Promise/A+标准所规定的特性。

但是你为什么不用糖方法(sugar methods)呢?建议你首先阅读 Promise: The Extension Problem这篇文章。更多关于Promise的信息,可以参考 Promise/A+标准。

你可能会问:如果大部分的库只暴露了回调的接口的话,那么我该如何使用Promise?

嗯,这个很简单,此时你唯一需要做的就是使用Promise来包裹含有回调的那个函数调用体。例如:

回调风格的代码可能是这样的:

function saveToTheDb(value) {    db.values.insert(value, function (err, user) {        if (err) throw err;        // todo: insert user to db    });}

现在我们将其改成支持Promise风格调用的代码:

function saveToTheDb(value) {      return new Promise(function(resolve, reject) {        db.values.insert(value, function(err, user) { // remember error first ;)            if (err) {                return reject(err); // don't forget to return here            }            resolve(user);        })    }}

已经有相当一部分的库或框架同时支持者两种方式了,即同时提供了回调风格和Promise风格的API接口。那么现在, 如果你也想对外提供一个库,最佳实践也是同时提供两种方式的接口。你可以轻松的使用如下方式来达到这个目的:

function foo(cb) {    if (cb) {    return cb();  }  return new Promise(function (resolve, reject) {  });}

或者更简单些,你可以从只提供Promise风格的接口开始后,并使用诸如 callbackify这样的工具来达到向后兼容的目的。其实Callbackify所做的工作和上面的代码片段类似,但在实现上使用了一个更通用的方法, 我建议你可以去阅读Callbackify的源代码。

生成器Generators/ yield

JavaScript 生成器是个相对较新的概念, 它是ES6(也被称为ES2015)的新特性。想象下面这样的一个场景:

当你在执行一个函数的时候,你可以在某个点暂停函数的执行,并且做一些其他工作,然后再返回这个函数继续执行, 甚至是携带一些新的值,然后继续执行。

上面描述的场景正是JavaScript生成器函数所致力于解决的问题。当我们调用一个生成器函数的时候,它并不会立即执行, 而是需要我们手动的去执行迭代操作(next方法)。也就是说,你调用生成器函数,它会返回给你一个迭代器。迭代器会遍历每个中断点。

function* foo () {    var index = 0;  while (index < 2) {    yield index++; //暂停函数执行,并执行yield后的操作  }}var bar =  foo(); // 返回的其实是一个迭代器console.log(bar.next());    // { value: 0, done: false }  console.log(bar.next());    // { value: 1, done: false }  console.log(bar.next());    // { value: undefined, done: true }  

更进一步的,如果你想更轻松的使用生成器函数来编写异步JavaScript代码,我们可以使用 co 这个库,co是著名的tj大神写的。

Co是一个为Node.js和浏览器打造的基于生成器的流程控制工具,借助于Promise,你可以使用更加优雅的方式编写非阻塞代码。

使用co,前面的示例代码,我们可以使用下面的代码来改写:

co(function* (){    yield Something.save();}).then(function() {  // success}).catch(function(err) {  //error handling});

你可能会问:如何实现并行操作呢?答案可能比你想象的简单,如下(其实它就是Promise.all而已):

yield [Something.save(), Otherthing.save()];  

Async/ await

在ES7(还未正式标准化)中引入了Async函数的概念,目前如果你想要使用的话,只能借助于babel 这样的语法转换器将其转为ES5代码。(提醒一点:我们现在讨论的是async关键字,而不是NPM中的async包)。

简而言之,使用async关键字,你可以轻松地达成之前使用生成器和co函数所做到的工作。当然,除了hack之外。

也许你会问,是否在ES7中有了async关键字,yield就变得不是那么重要了?

实际上,使用yield实现异步也不过是一种hack罢了,yield意味着懒次序(lazy sequences)和迭代器。 而await能够完美的分离这两点,首先让yield用于其最初的目的,其次使用await来执行异步操作。

在这背后,async函数实际使用的是Promise,也就是为什么async函数会返回一个Promise的原因。

因此,我们使用async函数来完成类似于前面代码所完成的工作,可以使用下面这样的方式来重新编写代码:

async function save(Something) {    try {    await Something.save(); // 等待await后面的代码执行完,类似于yield  } catch (ex) {    //error handling  }  console.log('success');} 

正如你看到的那样,使用async函数,你需要在函数声明的最前面加上async关键字。这之后,你可以在函数内部使用await关键字了,作用和之前的yield作用是类似的。

使用async函数完成并行任务与yiled的方式非常的相似,唯一不同的是,此时Promise.all不再是隐式的,你需要显示的调用它:

async function save(Something) {      await Promise.all[Something.save(), Otherthing.save()]}

Koa也支持async函数,如果你也在使用koa,那么你现在就可以借助babel使用这一特性了。

import koa from koa;  let app = koa();app.experimental = true;app.use(async function (){      this.body = await Promise.resolve('Hello Reader!')})app.listen(3000);  

拓展阅读

Hapi with generators

Koa

(责编:陈秋歌)

原文链接:The Evolution of Asynchronous JavaScript

译者简介:景庄,前端工程师,关注Node.js、前端工程化。个人博客: http://wwsun.github.com。

欢迎加入CSDN前端交流群2:465281214,进行前端技术交流。  

机器学习典范?iOS7中的Siri能主动学习如何发音 三星宣布关闭PC业务 主推便携设备和一体机 Web设计师必须掌握的六大设计策略 Facebook为什么要推Instagram视频分享功能? 天气预报(id后面的9位数字为城市代码)年月日,星期,当前时间(仅用于javascript) PHP 5.5.0发布 不再支持Windows XP和2003 专访ThinkPHP创始人刘晨:用最简单最快速的方式开发PHP应用 重构:仔细查看,改进代码 加速编码的17款最棒的CSS工具 生于微信:专访疯狂猜图CEO曹晓刚 谷歌:受感染的合法网站远比恶意网站危险性大 Mozilla正式发布Firefox 22应用程序开发者受益 支持3D游戏、视频通话和文件分享 直接拿来用!最火的前端开发项目(一) Salesforce.com和Oracle在云合作上达成长期协议 即将到来的数据中心僵尸末日,谁能成为最后的幸存者?! Andorid APK反逆向解决方案:梆梆加固原理探寻 科技拥抱设计:体验设计如何创新? Rails 4.0正式发布 命途多舛的webOS,两度易主,生生死死多少回 Citrix全面开源XenServer 为了三十亿人的网络幸福:Google投资O3b发射网络卫星 Windows 8.1中IE 11开始支持WebGL和SPDY/3 微软Build 2013开发者大会:盘点Windows 8.1的15个重大更新 瞧!这是摩托罗拉移动新Logo,你有什么感觉? 专访UEditor创始人战毅:打造最佳的用户编辑体验 Eclipse 4.3 正式版发布 代号Kepler 为兴趣而生 七大编程挑战项目,你敢来吗? iOS 7辅助功能:左右摇头控制iOS设备 挑战传统关系型数据库:Facebook图形数据库TAO揭秘 揭秘“棱镜计划”幕后的技术 你更新了吗?Visual Studio 2013 Preview和.NET 4.5.1同时发布 请问什么命令找开一个窗体的? 请问:如何从文件中获取icon并得到HBITMAP句柄? 如何在客户端打开一个word文件 MVP是个什么概念???? linux启动不了,Bringup loopback interface时出错,请问是什么原因? 帮帮忙!! 我海军一艘潜艇失事 70名官兵不幸全部遇难!! 明天朋友结婚,征集整人的法子 是谁删除了我贴?? 而且没有跟我说一声!!! 白天工作,晚上溜狗,爽呀!比大暑天喝了冰镇雪碧还爽! 我的jsp服务器是iis+TOMCAT+win2000pro 不知怎的每次用不了多久就显示出 网页无法显示 目前访问该 Web 站点的用户过多,我只是自已用怎么 终于有星了,高兴,散分(第一次散分,请斑竹手下留情) 我的刚装的2000进入启动界面时,进度条读到2/3时就蓝屏了! 请问在运行时向ActiveX控件中添加ActiveX控件的方法是什么? 高手请进:如何在WinNT以上系统进行BIOS读取! 毕业设计的问题,请各位大哥帮小弟一个忙 备份与恢复 数据备份与恢复 我用win2k,下载了php4.3.1,extension_dir是c:\php\ext 可是里面没有php_gd.dll,怎么办,到哪里可以down一个补上? 帮我一下:解决中文问题 新手问题:怎么在用ATL COM WIZARD已生成的dll加入MFC 请问如何删除系统? warton给大家散分来了! 求助,请问哪儿提供的域名空间最好? 新手上路,VB中用ODBC连接ACCESS 关于ORACLE中(多)表的备份和恢复问题 MM``狂给分^*^ 找人一同研究JUnit对于数据库的测试架构 怎样在程序中动态生成数据库(内存库)?求救高手 请问,怎样用本机作web服务器? 这样的夜晚 想起一些故人.... 各位的jbuilder是用什么命令运行的 刚学者求问 python+CGI 如何获得客户端IP Win2000上, 对话框没能弹出到桌面顶层 在静态上下文中不能引用非静态变量? 有没有高手可以举例讲解一下self的各种用法? 一个很困惑的问题:文字处理软件中,字体大小改变时,字符的高度,宽度怎么变化? 移动硬盘在重装系统时忘记拔下来。结果给误删了,求助!没有格式化的! 怎样创建自己的 Cursor ? 请问一下 这个是什么意思 public Properties() { this(null)} 在SQL7中日志满了,如何清除日志. ?????????? 一个编程习惯上的问题 为中国争口气!投中国的长城和布达拉宫一票!!恳请置顶! 菜鸟问题4。。。。 网上现在有没有用ASP.NET做的实例 vc.net为什么没classwizard 有关CDC的一个问题,有代码,请指教! 要陪老婆,兄弟们,给我顶住,我先闪了,..... javascript 能否取得客户端的IP? 关于删除xp_cmdshell的问题 一个四边形一定可以进行镶嵌 求泰勒斯威夫特的新专辑red里面come back...be here,we are never ever getting back together还有还有sad beautiful tragic,以及以前的safe and sound和you belong with me,back to december的伴奏,各位有多少都发给我吧, 家里挂镜子好吗 go to work by their car对吗 指南车为何人所造? 除哪一种外都是由细胞构成的?A,狗 B,烟草花叶病毒 C,蕨 D,向日葵请说明选择理由哦! 江西省九江市永修县立新乡车溪车溪中心组193号英语翻译 7上历史题传说谁造指南车 构成向日葵的组织有 改为复数形式啊 黄帝制造指南车反映出人们可能认识到什么现象? 如图所示,左侧是倾角为60°的斜面、右侧是 圆弧面的物体固定在水平地面上,圆弧面底端切线水平,一...如图所示,左侧是倾角为60°的斜面、右侧是圆弧面的物体固定在水平地面上,圆弧面底端 江西省新余市渝水区的邮政编码是多少 余额宝里,在金额相同的情况下,为什么七日年化收益的利率越高,反而收益越少呢?比如说,金额相同的情况下,七日年化收益的利率是4.9940%的收益(2.35)比七日年化收益的利率是4.7960%(2.89)的 他们相爱两年了.They have___each other for 2 years, 改为复数形式, 以余额宝的七日年化利率什么上涨什么下跌.a一定b可能c不可能,数学题 《我的伯父鲁迅先生》课后问题:“你想,四周黑洞洞的,还不容易碰壁吗?”找出类似的句子并解释 运用三角形和四边形进行ping平面镶嵌,个三角形和?个四边形可以进行平面镶嵌? 《我的伯父鲁迅先生 》四周黑洞洞比喻什么 help!math!已知abcd是正数,且满足a+b+c+d=4,用M表示a+b+c+d,c+d+a,d+a+b的最大值,则M的最小值是多少? 某超市在一楼和二楼之间安装有电梯天花板与地面平行请你根据图中数据计算回答:小某超市在一楼至二楼之间安装有电梯,天花板与地面平行,请你根据图中数据计算回答:小敏身高1.78m,她 英语翻译快1! 我的伯父鲁迅先生中“四周黑洞洞的,还不容易碰壁吗?”求理解 一辆拖拉机耕地,第一天耕了全部的1/3还多2公亩,第二天耕了剩下的1/2少1公亩·,这时还剩38公亩没耕完这块地有多少公亩 送分!今天倒数第二次 先到先得 无条件限制!速度进 I like this pink jacket改否定句;They like the school也改否定句并写出一般疑问句,作否定与肯定回答 拖拉机耕地,第一天种了1/3还多30公亩,第二天种的比剩下的1/2少15公亩,这时还剩下585公亩,求这块有多少公亩? 今天倒数第二次送分!先到先得!无条件限制! They like super robots(否定句)This pair of gloves is yellow(复数句)The are(horses)in English(提问 关于毛泽东的诗词 小报的题目帮我起个题目,5—7个字左右好的追加悬赏5——不等 there+was+a+small+house+many+year+ago.+变一般疑问句怎么变着急 我的伯父鲁迅先生++++++++++++++四周黑洞洞的比喻什么++++++碰壁比喻什么 毛泽东都有哪些诗词(题目,题材) 江西省新余市的邮政编码是多少呀 如图,如果直线L 的表达式为y=kx+b,那么关于x的不等式kx+b>0的解集是______________如果直线L 的表达式为y=kx+b,那么关于x的不等式kx+b>0的解集是______________,kx+b ________are all Chinese a)We ,you and they b)you ,they and we c)he ,you and i d)they ,you and we这道题我觉得先a,可为什么答案上选b 江西省新余市东山雅筑邮政编码 语文一道题;连( )带( )例;连(蹦)带(跳)英语题目;open your books(改为否定句,但意思不变哦 ) 同一种四边形能够进行平面镶嵌吗? bamboo的复数复制搜索说出为什么复制搜索 海带细胞中积累的碘的方式是什么? 同一种四边形一定能进行平面镶嵌是真命题吗? 四周黑洞洞的,难道还不容易碰壁吗?《我的伯父鲁迅先生》 这句话用的是什么修辞手法 Open the gate.please 改为否定句,句意不变 Kitty is my sister 对画线提问 Kitty是画线的 任何同一种四边形都能够进行平面镶嵌吗 ------- 目前非美元与人民币汇率的波动幅度为中国人民银行公布的该货币当日交易中间价的多少?进行提问 “任意四边形都可以密铺”这句话对吗? I,you and he are all teachers.其中有哪处错误?怎么改? The dress,________ a flower on it,is very beautiful. 任意四边形都可以密铺吗 生命生命杏林子题目用了2个生命会不会重复 苹果含维生素C吗?或含那些维生素? 每2个参加宴会的人见面时握一次手,N个人握了几次 以“生命价值”这个词为题目写一段话 【注】:讲起来只需2、3分钟就行,写的好的加分, Mrs white (have)a beautiful dress 的水母、海带,陆地上的蜥蜴、小草等 生物细胞中含量最多的是 正八边形和正四边形在镶嵌时需()个正八边形和()个正四边形 The beautiful dress cost her(100yuan)(把括号里的单词进行提问) 初中生物学里有哪些海洋下的食物?例:海带请说出这些的名字, 韩国仁川海警截获三艘“非法捕捞”中国法媒曝萨科齐下台后电子档案遭非法侦察萌翻!日本熊猫造型食物美味诱人受热捧美国安局将韩国列为主要监听对象 韩方美国国务卿克里访波兰 有望就监听事件印度将发射火星探测器 欲当太空竞赛“河北“超生女婴被抱走”事件新进展:警美媒:大黄鸭在北京受欢迎 为中国经济梁振英:菲人质事件若1个月没成果将采孙杨被行政拘留后需穿囚服不剃光头 伙曝孙杨在拘留所飙泪 “拘留 三停”创上海天降“粪便雨” 民航否认为飞机泄象山将公积金最高贷款限额由每户60万浙江三季度游客满意度嘉兴、宁波、杭州南京空气质量排名江苏全省倒数第二大学校园现\"女汉子\"求爱条幅:求浙江省水龙头抽检将添重金属析出量杭州推广路灯节能系统 每天可节约用电杭州十大产业最缺研发人才 金融服务业伊利刘世界:新型岗位上的新新人类最高检民主生活会:抓好整改落实 推进女性养生:睡前三个小习惯年轻十五岁【广东:坠楼男童脑死亡 殡仪馆外握手百米荒草地着火李娜决赛对手赢球后抱头痛哭 外媒:或福建泉州市人大常委会原副主任骆国清被中国海军远海编队将在南海与潜艇合练 春运首周航班同比增三成多让群众安安心心过大年海南冬季瓜菜备战春节黄金周,安全服务应先行海口市举行2014年迎春团拜会曼联又输了!辽宁抚顺西露天矿附近出现3000多米危险!婴儿无人看管 爬出八楼窗台中国公证遗嘱备案查询平台建成使用今年津城教育看点多 中高考改革方案上做勤政为民务实清廉好干部我省多措并举严防禽流感联想23亿美元收购IBMX86海口市环境空气质量日报春节推升猪牛羊肉水果涨价预期
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘