网上有不少关于async/await的学习文章,我也是经过这些文章学习了解async的,可是不总结一下,总以为没有真正学到。若有错误的地方还请多多指出。javascript
有人说它是JS编程异步的“终极解决方案”,终不终极不知道,事物老是在发展的嘛,可是能被冠上这么个头衔也绝非等闲之辈了😊。async是“异步的”,await是“等待”,async是形容词,await是动词,那么async形容的函数告诉别人这是个包含异步的“异步的函数”,而await要等待某个东西的到来。a/a给了咱们从新使用try catch的权力,而且规定await必须写在async形容的函数中。使用a/a要对Promise有所理解,那还要从回调提及。html
JS是一根筋的(单线程),一次只执行一个任务,后面的要等前面的完成才行, 若是某个任务要占用很长时间,那么后面的任务就都要等着。因此java
JS将任务的执行模式分红两种:同步(Synchronous)和异步(Asynchronous)。 地址
回调函数就是“异步“的方法之一。你们对回调很熟啦,回调会产生一个问题-回调地狱,两层回调还好,三层彷佛也能够接受,硬着头皮四层也行,五层要不要写,咬咬牙六层就行了。。。最后,一首杨宗纬的洋葱送给本身。一层一层剥开回调,找到最终的小可爱。
好比下面的栗子:编程
a1(function(res) { d2(res, function(newRes) { a3(newRes, function(finalRes) { console.log('a3: ' + finalRes); }, a1FCb); }, a2FailCb); }, a3FailCb);
另外,当年我还年轻的时候,初试回调,在回调函数中花样百出的尝试return
,在回调外面也取不到return的值,大概下面这个样子promise
var a = '' function fool(){ setTimeout(() => { return 'hi'// 或者 }, 1000); } a = fool() console.log(a) //undefined 由于setTimeout异步执行,a=fool()执行在timeout以前,而此时的fool()并内有return任何东西
回调让咱们失去了直接“使用return”的方式,那来看看Promise。异步
顾名思义,promise是承诺的意思,承诺在将来是能够兑现的,promise能够有效的解决回调地狱,并且给了咱们使用return的权力。只不过它的return还是一个承诺。对于promise的学习可参考promise MDN和Promise MDN。async
一个Promise
有如下几种状态:
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操做成功完成。
rejected: 意味着操做失败。
以下一个利用Promise构造函数声明的实例ide
new Promise(function(resolve,reject){//...})
resolve 和 reject 函数被调用时,分别将promise的状态改成fulfilled(完成)或rejected(失败),这两个状态不能同时出现,两个状态完成时,分别调用promise的then方法中对应的onfulfilled 和onrejected 函数。举个例子:函数
function a(val){ return new Promise(function(resolve,reject){ if(val === 1){ resolve(val) } else { reject('bad val') } }) }
函数a接收一个参数,返回一个promise实例,当参数是指望的1时,表示操做成功,其余值被认为操做失败。那么若是执行如下操做学习
a(1).then(function(res){ console.log('onfulfilled '+ res) },function(errMsg){ console.log('onrejected '+ errMsg) }) //会log出'onfulfilled 1'
该操做a(1)
会调用函数a内部promise实例的resolve函数,把该promise的状态变成了fulfilled,因此以后会调用then
函数里onfulfilled的函数。
另外,对于操做失败的状态,除了在then中指定对应的onreject函数外,也可使用catch
,使用catch的好处在于,若是是多个异步操做,只须要指定一个catch便可,不用为每层then都指定一个onreject函数。举个例子:
有以下三层回调:
fun1(function(res1){ fun2(function(res1){ var res2 = res1 + 'hello' fun3(function(res2){ var res3 = res2 + 'hi' console.log('the final res ' + res3) },fun3FailCb) },fun2FailCb) },fun1FailCb)
改为promise写法后:
fun1() .then(function(res1){ return fun2(res1+'hello') }) .then(function(res2){ return fun3(res2+'hi') }) .then(function(res3){ console.log('the final res' + res3) }) .catch(function(err){ console.log('something bad occured') })
清爽不少。then的链写多了,看起来也很烦啊,有没有更简洁的方法?有!
async/await
是一个语法糖,他和promise关系紧密,可参考async MDN。
当调用一个 async 函数时,会返回一个 Promise 对象。当这个 async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值;当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。
回到开篇说的,async所形容的函数告诉别人这是个包含异步的“异步的函数”,也就是async的函数会返回一个promise (同步的代码也不要紧,只不过没啥意义了)。await要等的就是其余async函数返回的这个promise,promise状态成功,await等到的是resolve中的值,promise状态失败,await等到的是reject中的错误信息,换句话说,被try/catch中的catch到了。举个例子:
async function f1(val){ if(val === 1){ return val } else { throw 'not 1' } } //调用f1(val)时,会自动返回一个包装好的promise async function f2(val2){ try{ var res1 = await f1(val2) console.log('res1' , res1) }catch(errmsg){ console.log('catch ', errmsg) } }
分别执行f2(1)和f2(3)查看log结果。
改写前面的三层回调
async function fun1(){ return res1 } async function fun2(val){ return val + 'hello' } async function fun3(val){ return val + 'hi' } async function fun4(){ try{ var res1 = await fun1() var res2 = await fun2(res1) var res3 = await fun3(res2) console.log('the final res ', res3) // other operation with res3/res2/res1... }catch(err){ console.log('something bad') } }
至关清爽。在async内,await会阻塞后面的程序执行,直到promise的状态完成(成功或失败)。