怎么评价异步方案promise,await,async,yield和await

点击阅读原文
我要该,理由是:
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)async / await:更好的异步解决方案
在实际开发中总会遇到许多异步的问题,最常见的场景接口请求之后一定要等一段时间才能得到结果,如果遇到多个接口前后依赖,那么问题就变得复杂。大家都一直在尝试使用更好的方案来解决这些问题。
在实际开发中总会遇到许多异步的问题,最常见的场景接口请求之后一定要等一段时间才能得到结果,如果遇到多个接口前后依赖,那么问题就变得复杂。大家都一直在尝试使用更好的方案来解决这些问题。最开始只能利用回调函数,后来开始有人使用Promise的思维来搞定。到ES6中开始支持原生的Promise,引入Generator函数。
直到ES7,有了async/await。
这是一个用同步的思维来解决异步问题的方案。
我想很多人可能还不太分得清同步与异步的区别。如果你已经彻底了解了事件循环,那么想必对异步的概念应该非常了解。当我们发出了请求,并不会等待响应结果,而是会继续执行后面的代码,响应结果的处理在之后的事件循环中解决。那么同步的意思,就是等结果出来之后,代码才会继续往下执行。
我们可以用一个两人问答的场景来比喻异步与同步。A向B问了一个问题之后,不等待B的回答,接着问下一个问题,这是异步。A向B问了一个问题之后,然后就笑呵呵的等着B回答,B回答了之后他才会接着问下一个问题。
那么我们先记住这个特点,async/await使用同步的思维,来解决异步的问题。在继续讲解它的语法与使用之前,我们先介绍一下如何在我们的开发环境中支持该语法。
如果你已经知道如何配置,可跳过
一、如何在自己的开发环境中支持async/await语法
这里主要介绍两种方式。
1. webpack中支持该语法
首先在当前项目中使用npm下载babel-loader。
然后在配置文件webpack.confing.dev.js中配置,在module.exports.module.rules中添加如下配置元素即可。
如果你使用最新版本的create-react-app或者vue-cli来构建你的代码,那么它们应该已经支持了该配置。
2. gulp中支持该语法
首先安装gulp插件
然后编写任务/
二、如何使用
async函数是Generator的一个语法糖。如果你不知道Generator是什么函数也没有关系,我们只需要知道async函数实际上返回的是一个Promise对象即可。
在声明函数时,前面加上关键字async,这就是async的用法。当我们用console.log打印出上面声明的函数fn,我们可以看到如下结果:
很显然,fn的运行结果其实就是一个Promise对象。因此我们也可以使用then来处理后续逻辑。
await的含义为等待。意思就是代码需要等待await后面的函数运行完并且有了返回结果之后,才继续执行下面的代码。这正是同步的效果。
但是我们需要注意的是,await关键字只能在async函数中使用。并且await后面的函数运行后必须返回一个Promise对象才能实现同步的效果。
当我们使用一个变量去接收await的返回值时,该返回值为Promise中resolve出来的值。
运行这个例子我们可以看出,当在async函数中,运行遇到await时,就会等待await后面的函数运行完毕,而不会直接执行next code。
如果我们直接使用then方法的话,想要达到同样的结果,就不得不把后续的逻辑写在then方法中。
很显然如果使用async/await的话,代码结构会更加简洁,逻辑也更加清晰。
在Promise中,我们知道是通过catch的方式来捕获异常。而当我们使用async时,则通过try/catch来捕获异常。
如果有多个await函数,那么只会返回第一个捕获到的异常。
在实践中我们遇到异步场景最多的就是接口请求,那么这里就以jquery中的$.get为例简单展示一下如何配合async/await来解决这个场景。
为了保证逻辑的完整性,在实践中try/catch必不可少。总之,不处理错误逻辑的程序员不是好程序员。
与Promise相比,个人认为async/await有一定的简洁性,但也并非就比Promise有绝对的优势,因此只能算是提供了另外一种稍好的方式,至于大家学习之后选择哪种方式来解决自己的问题,这仅仅只是你的个人喜好问题。
本文已收录于以下专栏:
相关文章推荐
第一个例子
Async/Await应该是目前最简单的异步方案了,首先来看个例子。
这里我们要实现一个暂停功能,输入N毫秒,则停顿N毫秒后才继续往下执行。
var sleep = func...
async await处理ajax
随着js的发展,在解决回调地狱问题的方案上,解决方案逐渐更新,有promise、generator和现在的async都是比较常见的;
这个解决方案就是把异步用同步的方式写出来,...
看到了这样的一篇文章,觉得写的不错,与大家分享:
异步技术能使得应用程序的总吞吐量得到显著提升,但这并不是无偿的。异步函数往往比其同步替代方案稍慢一些,而且如果您不介意采用它还会增加相当大的内存压力...
以前,我们或许用过Thread,在主线程执行的时候,新开另一个新线程,来执行新方法。           今天看别人发给我的一段代码的时候发现了一个不认识的await,但是又感觉很熟悉的样子,感觉是线...
对于js关于异步是它的一大特点,但有时候也成为了一大难点,金字塔的地狱式回调,现在来浅谈关于js的异步处理方案。众所周知的promise
node 的高并发是新的特性,但是回调使其变得有点尴...
async和await这一组关键字是.Net4.5新增的一种异步编程方式,今天就根据自己的理解讲讲async和await与Task之间的关系。什么是异步拿操作系统来说,CPU就具有异步性。当在进行IO...
Iterator、Generator、async、await
参考ECMAScript 6 入门
Iterator 遍历器说明
Iterator(遍历器、迭代器)是一种接口,他为不同的数据结构...
他的最新文章
讲师:刘文志
讲师:陈伟
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)Async/Await替代Promise的6个理由 - CNode技术社区
Fundebug是全栈JavaScript实时错误监测平台,能够及时发现您的应用错误,助您提升用户体验。
译者按: Node.js的异步编程方式有效提高了应用性能;然而回调地狱却让人望而生畏,Promise让我们告别回调函数,写出更优雅的异步代码;在实践过程中,却发现Promise并不完美;技术进步是无止境的,这时,我们有了Async/Await。
为了保证可读性,本文采用意译而非直译。
Node.js 7.6已经支持async/await了,如果你还没有试过,这篇博客将告诉你为什么要用它。
Async/Await简介
对于从未听说过async/await的朋友,下面是简介:
async/await是写异步代码的新方式,以前的方法有回调函数和Promise。
async/await是基于Promise实现的,它不能用于普通的回调函数。
async/await与Promise一样,是非阻塞的。
async/await使得异步代码看起来像同步代码,这正是它的魔力所在。
Async/Await语法
示例中,getJSON函数返回一个promise,这个promise成功resolve时会返回一个json对象。我们只是调用这个函数,打印返回的JSON对象,然后返回&done&。
使用Promise是这样的:
const makeRequest = () =&
.then(data =& {
console.log(data)
return &done&
makeRequest()
使用Async/Await是这样的:
const makeRequest = async () =& {
console.log(await getJSON())
return &done&
makeRequest()
它们有一些细微不同:
函数前面多了一个aync关键字。await关键字只能用在aync定义的函数内。async函数会隐式地返回一个promise,该promise的reosolve值就是函数return的值。(示例中reosolve值就是字符串&done&)
第1点暗示我们不能在最外层代码中使用await,因为不在async函数内。
// 不能在最外层代码中使用await
await makeRequest()
// 这是会出事情的
makeRequest().then((result) =& {
// 代码
await getJSON()表示console.log会等到getJSON的promise成功reosolve之后再执行。
为什么Async/Await更好?
由示例可知,使用Async/Await明显节约了不少代码。我们不需要写.then,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量,还避免了嵌套代码。这些小的优点会迅速累计起来,这在之后的代码示例中会更加明显。
2. 错误处理
Async/Await让try/catch可以同时处理同步和异步错误。在下面的promise示例中,try/catch不能处理JSON.parse的错误,因为它在Promise中。我们需要使用.catch,这样错误处理代码非常冗余。并且,在我们的实际生产代码会更加复杂。
const makeRequest = () =& {
.then(result =& {
// JSON.parse可能会出错
const data = JSON.parse(result)
console.log(data)
// 取消注释,处理异步代码的错误
// .catch((err) =& {
//
console.log(err)
// })
} catch (err) {
console.log(err)
使用aync/await的话,catch能处理JSON.parse错误:
const makeRequest = async () =& {
// this parse may fail
const data = JSON.parse(await getJSON())
console.log(data)
} catch (err) {
console.log(err)
3. 条件语句
下面示例中,需要获取数据,然后根据返回数据决定是直接返回,还是继续获取更多的数据。
const makeRequest = () =& {
return getJSON()
.then(data =& {
if (data.needsAnotherRequest) {
return makeAnotherRequest(data)
.then(moreData =& {
console.log(moreData)
return moreData
console.log(data)
return data
这些代码看着就头痛。嵌套(6层),括号,return语句很容易让人感到迷茫,而它们只是需要将最终结果传递到最外层的Promise。
上面的代码使用async/await编写可以大大地提高可读性:
const makeRequest = async () =& {
const data = await getJSON()
if (data.needsAnotherRequest) {
const moreData = await makeAnotherRequest(data);
console.log(moreData)
return moreData
console.log(data)
return data
你很可能遇到过这样的场景,调用promise1,使用promise1返回的结果去调用promise2,然后使用两者的结果去调用promise3。你的代码很可能是这样的:
const makeRequest = () =& {
return promise1()
.then(value1 =& {
return promise2(value1)
.then(value2 =& {
return promise3(value1, value2)
如果promise3不需要value1,可以很简单地将promise嵌套铺平。如果你忍受不了嵌套,你可以将value 1 & 2 放进Promise.all来避免深层嵌套:
const makeRequest = () =& {
return promise1()
.then(value1 =& {
return Promise.all([value1, promise2(value1)])
.then(([value1, value2]) =& {
return promise3(value1, value2)
这种方法为了可读性牺牲了语义。除了避免嵌套,并没有其他理由将value1和value2放在一个数组中。
使用async/await的话,代码会变得异常简单和直观。
const makeRequest = async () =& {
const value1 = await promise1()
const value2 = await promise2(value1)
return promise3(value1, value2)
下面示例中调用了多个Promise,假设Promise链中某个地方抛出了一个错误:
const makeRequest = () =& {
return callAPromise()
.then(() =& callAPromise())
.then(() =& callAPromise())
.then(() =& callAPromise())
.then(() =& callAPromise())
.then(() =& {
throw new Error(&oops&);
makeRequest()
.catch(err =& {
console.log(err);
// output
// Error: oops at callAPromise.then.then.then.then.then (index.js:8:13)
Promise链中返回的错误栈没有给出错误发生位置的线索。更糟糕的是,它会误导我们;错误栈中唯一的函数名为callAPromise,然而它和错误没有关系。(文件名和行号还是有用的)。
然而,async/await中的错误栈会指向错误所在的函数:
const makeRequest = async () =& {
await callAPromise()
await callAPromise()
await callAPromise()
await callAPromise()
await callAPromise()
throw new Error(&oops&);
makeRequest()
.catch(err =& {
console.log(err);
// output
// Error: oops at makeRequest (index.js:7:9)
在开发环境中,这一点优势并不大。但是,当你分析生产环境的错误日志时,它将非常有用。这时,知道错误发生在makeRequest比知道错误发生在then链中要好。
最后一点,也是非常重要的一点在于,async/await能够使得代码调试更简单。2个理由使得调试Promise变得非常痛苦:
不能在返回表达式的箭头函数中设置断点
如果你在.then代码块中设置断点,使用Step Over快捷键,调试器不会跳到下一个.then,因为它只会跳过异步代码。
使用await/async时,你不再需要那么多箭头函数,这样你就可以像调试同步代码一样跳过await语句。
Async/Await是近年来JavaScript添加的最革命性的的特性之一。它会让你发现Promise的语法有多糟糕,而且提供了一个直观的替代方法。
对于Async/Await,也许你有一些合理的怀疑:
它使得异步代码不在明显: 我们已经习惯了用回调函数或者.then来识别异步代码,我们可能需要花数个星期去习惯新的标志。但是,C#拥有这个特性已经很多年了,熟悉它的朋友应该知道暂时的稍微不方便是值得的。
Node 7不是LTS(长期支持版本): 但是,Node 8下个月就会发布,将代码迁移到新版本会非常简单。
欢迎加入的Node.js技术交流群: 。
转载时请注明作者以及本文地址:
里面都是promise,还说替代promise,能不搞笑么?很长很长一段时间都会共存,何谈替代
同意楼上,另外不相关联的异步操作,希望大家别一直用await,严重影响效率,可以来一发await Promise.all()。
对对对,没事来一发并行的
v8在下一个版本里对async还有4倍以上的效率优化,慢慢来吧,哈哈
额, Promise 还没写麻溜 , 又来了个新的.让我缓缓
Await/Async的确是基于Promise的。但是,直接用Promise写异步和使用Await/Async写异步,是两种不同的写法吧?那不是替代是什么?
处理的效率何在?
其实有个协程概念,原理(c++和node.js实现) 的东西可以深入研究一下啊。。。
哪里影响效率了?
我觉得还是坐等LTS全面支持再说吧,以后再改咯
promise 也避不开,怎么说是替代
写起来好看一点点
据我所知await/async并非基于Promise,而是基于yield和generator(内部编译成yield,只不过返回值是promise而已)。
写法不一样了,不就是替代吗?然后好处好像也不止是好看吧?好歹列了6条理由啊
返回值是promise难道就不算是基于promise?
C++部分确实是Generator
能并发的地方为什么不并发,还要用await 干等着上一个的结果返回
其实我是赞同你的
并发操作确实不能用await,所以我觉得Promise今后唯一用得着的地方就是Promise.all和Promise.race这两个了。普通的Promise好像真没啥用了。
async/await 并不是完整的 Promise 替代,使用 async/await 之前仍需要了解 Promise 的概念,并且在一些情况下仍然必须使用 Promise,例如没办法在函数返回前提前 reslove 返回的 Promise 等。
此外我觉得使用 async/await 会不自觉地让人不愿意使用 Promise.all,将原本可以并行的操作串行化。
其实如果你的项目大部分都用了 Promise,就没有必要去处理同步异常,因为调用者是会捕捉到同步异常的。
前两天买了一个域名
,有兴趣的朋友可以联系我一起来为这个站点撰写内容,写一份关于不要使用 async/await 的倡议。
我写过很大型的异步逻辑,中间一层用到Promise.all,同时外层和内层都用await,用非常美观的函数式风格实现,举例如下(该例子先取得一组用户名,然后向数据库查询这些用户的分数,返回其中分数超过50的用户):
let fn = async () =& {
let loginNames = await getLoginNames();
let result = (await Promise.all(
loginNames.map(async name =& {
let user = await db.collection(&users&).findOne({loginName: name});
return user.score & 50 ? user :
)).filter(m =& m !== null);
阔以学习 ,Promise和Await/Async一起用,直接拒绝不是什么好办法。
为啥不要使用 async/await ?
精子666666,哈哈哈哈哈。
例子中promise多层回调是中了以前固定思维的毒,完全可以返回在最外层写then
那你写给我看看
没有Promise,你await什么呢?应该是用替代二字不够准确。
倡议不使用async/await,这…-_-
替代的是写异步代码的方法。。。谁说要把Promise去掉啊
CNode 社区为国内最专业的 Node.js 开源技术社区,致力于 Node.js 的技术研究。
服务器赞助商为
,存储赞助商为
,由提供应用性能服务。
新手搭建 Node.js 服务器,推荐使用无需备案的在 SegmentFault,解决技术问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
一线的工程师、著名开源项目的作者们,都在这里:
获取验证码
已有账号?
标签:至少1个,最多5个
自从Node的7.6版本,已经默认支持async/await特性了。如果你还没有使用过他,或者对他的用法不太了解,这篇文章会告诉你为什么这个特性“不容错过”。本文辅以大量实例,相信你能很轻松的看懂,并了解Javascript处理异步的一大杀器。
文章灵感和内容借鉴了,英文好的同学可以直接戳原版参考。
初识Async/await
对于还不了解Async/await特性的同学,下面一段是一个“速成”培训。Async/await 是Javascript编写异步程序的新方法。以往的异步方法无外乎回调函数和Promise。但是Async/await建立于Promise之上。对于Javascript处理异步,是个老生常谈却历久弥新的话题:
从最早的回调函数,到 Promise 对象,再到 Generator 函数,每次都有所改进,但又让人觉得不彻底。它们都有额外的复杂性,都需要理解抽象的底层运行机制。异步编程的最高境界,就是根本不用关心它是不是异步。
async 函数就是隧道尽头的亮光,很多人认为它是异步操作的终极解决方案。
Async/await语法
试想一下,我们有一个getJSON方法,该方法发送一个异步请求JSON数据,并返回一个promise对象。这个promise对象的resolve方法传递异步获得的JSON数据。具体例子的使用如下:
const makeRequest = () =&
.then(data =& {
console.log(data)
return "done"
makeRequest()
在使用async/await时,写法如下:
const makeRequest = async () =& {
console.log(await getJSON())
return "done"
makeRequest()
对比两种写法,针对第二种,我需要进一步说明:
1)第二种写法(使用async/await),在主体函数之前使用了async关键字。在函数体内,使用了await关键字。当然await关键字只能出现在用async声明的函数体内。该函数会隐式地返回一个Promise对象,函数体内的return值,将会作为这个Promise对象resolve时的参数。可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
2)示例中,await getJSON() 说明console.log的调用,会等到getJSON()返回的promise对象resolve之后触发。
我们在看一个例子加强一下理解,该例子取自阮一峰大神的《ECMAScript 6 入门》一书:
function timeout(ms) {
return new Promise((resolve) =& {
setTimeout(resolve, ms);
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
asyncPrint('hello world', 50);
上面代码指定50毫秒以后,输出hello world。
Async/await究竟好在哪里?
那么,同样是处理异步操作,Async/await究竟好在哪里呢?我们总结出以下6点。
简约而干净Concise and clean
我们看一下上面两处代码的代码量,就可以直观地看出使用Async/await对于代码量的节省是很明显的。对比Promise,我们不需要书写.then,不需要新建一个匿名函数处理响应,也不需要再把数据赋值给一个我们其实并不需要的变量。同样,我们避免了耦合的出现。这些看似很小的优势其实是很直观的,在下面的代码示例中,将会更加放大。
错误处理Error handling
Async/await使得处理同步+异步错误成为了现实。我们同样使用try/catch结构,但是在promises的情况下,try/catch难以处理在JSON.parse过程中的问题,原因是这个错误发生在Promise内部。想要处理这种情况下的错误,我们只能再嵌套一层try/catch,就像这样:
const makeRequest = () =& {
.then(result =& {
// this parse may fail
const data = JSON.parse(result)
console.log(data)
// uncomment this block to handle asynchronous errors
// .catch((err) =& {
console.log(err)
catch (err) {
console.log(err)
但是,如果用async/await处理,一切变得简单,解析中的错误也能轻而易举的解决:
const makeRequest = async () =& {
// this parse may fail
const data = JSON.parse(await getJSON())
console.log(data)
catch (err) {
console.log(err)
条件判别Conditionals
想象一下这样的业务需求:我们需要先拉取数据,然后根据得到的数据判断是否输出此数据,或者根据数据内容拉取更多的信息。如下:
const makeRequest = () =& {
return getJSON()
.then(data =& {
if (data.needsAnotherRequest) {
return makeAnotherRequest(data)
.then(moreData =& {
console.log(moreData)
return moreData
console.log(data)
return data
这样的代码会让我们看的头疼。这这么多层(6层)嵌套过程中,非常容易“丢失自我”。使用async/await,我们就可以轻而易举的写出可读性更高的代码:
const makeRequest = async () =& {
const data = await getJSON()
if (data.needsAnotherRequest) {
const moreData = await makeAnotherRequest(data);
console.log(moreData)
return moreData
console.log(data)
return data
中间值Intermediate values
一个经常出现的场景是,我们先调起promise1,然后根据返回值,调用promise2,之后再根据这两个Promises得值,调取promise3。使用Promise,我们不难实现:
const makeRequest = () =& {
return promise1()
.then(value1 =& {
// do something
return promise2(value1)
.then(value2 =& {
// do something
return promise3(value1, value2)
如果你难以忍受这样的代码,我们可以优化我们的Promise,方案是使用Promise.all来避免很深的嵌套。就像这样:
const makeRequest = () =& {
return promise1()
.then(value1 =& {
// do something
return Promise.all([value1, promise2(value1)])
.then(([value1, value2]) =& {
// do something
return promise3(value1, value2)
Promise.all这个方法牺牲了语义性,但是得到了更好的可读性。但是其实,把value1 & value2一起放到一个数组中,是很“蛋疼”的,某种意义上也是多余的。
同样的场景,使用async/await会非常简单:
const makeRequest = async () =& {
const value1 = await promise1()
const value2 = await promise2(value1)
return promise3(value1, value2)
错误堆栈信息Error stacks
想象一下我们链式调用了很多promises,一级接一级。紧接着,这条promises链中某处出错,如下:
const makeRequest = () =& {
return callAPromise()
.then(() =& callAPromise())
.then(() =& callAPromise())
.then(() =& callAPromise())
.then(() =& callAPromise())
.then(() =& {
throw new Error("oops");
makeRequest()
.catch(err =& {
console.log(err);
// Error: oops at callAPromise.then.then.then.then.then (index.js:8:13)
此链条的错误堆栈信息并没用线索指示错误到底出现在哪里。更糟糕的事,他还会误导开发者:错误信息中唯一出现的函数名称其实根本就是无辜的。我们再看一下async/await的展现:
const makeRequest = async () =& {
await callAPromise()
await callAPromise()
await callAPromise()
await callAPromise()
await callAPromise()
throw new Error("oops");
makeRequest()
.catch(err =& {
console.log(err);
// Error: oops at makeRequest (index.js:7:9)
也许这样的对比,对于在本地开发阶段区别不是很大。但是想象一下在服务器端,线上代码的错误日志情况下,将会变得非常有意义。你一定会觉得上面这样的错误信息,比“错误出自一个then的then的then。。。”有用的多。
调试Debugging
最后一点,但是也是很重要的一点,使用async/await来debug会变得非常简单。在一个返回表达式的箭头函数中,我们不能设置断点,这就会造成下面的局面:
const makeRequest = () =& {
return callAPromise()
.then(()=&callAPromise())
.then(()=&callAPromise())
.then(()=&callAPromise())
.then(()=&callAPromise())
我们无法在每一行设置断点。但是使用async/await时:
const makeRequest = async () =& {
await callAPromise()
await callAPromise()
await callAPromise()
await callAPromise()
Async/await是近些年来JavaScript最具革命性的新特性之一。他让读者意识到使用Promise存在的一些问题,并提供了自身来代替Promise的方案。当然,对这个新特性也有一定的担心,体现在:他使得异步代码变的不再明显,我们好不容易已经学会并习惯了使用回调函数或者.then来处理异步。新的特性当然需要时间成本去学习和体会;退回来说,熟悉C#语言的程序员一定会懂得这些学习成本是完全值得的。
Happy Coding!
PS: 作者,欢迎通过代码各种形式交流。
4 收藏&&|&&38
你可能感兴趣的文章
15 收藏,2.6k
32 收藏,3.6k
26 收藏,4k
async/await是搭配promise一起使用的,怎么能说是完爆?
`async/await`是搭配promise一起使用的,怎么能说是完爆?
明明就是翻译过来,还要说成是原文,你这和原文的相似度也有百分之九十了吧
明明就是翻译过来,还要说成是原文,你这和原文的相似度也有百分之九十了吧
....楼上+1。。。。。这标题有毒。。。!~!~
....楼上+1。。。。。这标题有毒。。。!~!~
分享到微博?
我要该,理由是:}

我要回帖

更多关于 yield promise 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信