<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本篇,帶你讀懂async~await間的浪漫。
關於非同步處理問題,ES5的回撥讓我們陷入回撥地獄輪迴,後來ES6的Promise(Promise不瞭解?點這瞭解)讓我們脫離輪迴,終於,ES7的async-await帶我們走向光明。今天我們就來學習一夏 async-await,看看與Promise有何聯絡和區別。
async函數返回一個 Promise 物件,可以使用then方法新增回撥函數。舉例說明:
// async返回的是Promise物件? async function testAsync() { return 'hello';//上篇文章Promise物件的返回值如果不是Promise,會通過Promise.resolve()轉化為Promise,再進行處理 } const result = testAsync() console.log(result);//Promise { 'hello' } 說明async返回的是Promise物件
那既然async返回的是Promise物件,那麼async後面的函數可以接.then()或者.catch()...嘛?我們試一試就知道了。
// async返回的是Promise物件,並且可以接Promise的方法? async function testAsync() { // await await等待還是promise物件 return 'hello' } testAsync() .then((result)=>{ console.log(result); }) .catch((error)=>{ console.log(error); }) //hello 媽耶!列印了!說明async返回的是Promise物件,並且可以接Promise的方法,並且!!!預設狀態是resolved的
上面程式碼說明,async函數內部return語句返回的值,會成為then方法回撥函數的引數
當async函數內部丟擲錯誤的時候,會導致返回的 Promise 物件變為reject狀態。丟擲的錯誤物件會被.then()方法的第二個回撥函數接收或者.catch()方法回撥函數接收到。
// async函數內部丟擲錯誤或者Promise狀態為reject async function testError(){ //throw new Error('出錯啦~~'); await Promise.reject('出錯了');//await前面有return和沒有return效果一樣 } testError() // .then(()=>{},(error)=>{console.log(error);}) .catch(error=>{console.log(error);}) //Error: 出錯啦~~
await命令後面是一個 Promise 物件,返回該物件的結果。如果不是 Promise 物件,就直接返回對應的值。程式碼說明:
// await async function getName(){ // return '來自星星的你'; return await '來自星星的你';//上面直接return等價於這個return } getName() .then(result=>{console.log(result);}) //來自星星的你
await的使用,必須要有async。這便是async-await的浪漫所在了:async返回的是一個Promise物件,await等待的就是這個Promise物件,所以await不能沒有async(但是async可以沒有await)。有沒有被浪漫到?反正我是醉了。如果await沒有async會怎麼樣?報錯:
// await沒有async會報錯 function testAwait(){ return await '西紅柿炒辣椒' } testAwait() .catch(error=>{ console.log(error); }) //SyntaxError: await is only valid in async function
// async封裝Promise async function fn1() { return '喜羊羊與灰太狼';// //相當於return Promise.resolve('喜羊羊與灰太狼') const data = await fn1();//接收data值 } fn1()//執行async函數,返回的是一個Promise物件 .then(data => { console.log('content =', data) }) //content = 喜羊羊與灰太狼
// await---.then() async function getName(){ const operate=Promise.resolve('白雪公主')//執行函數 const name= await operate //await相當於Promise的then operate.then(name=>{}) console.log('name:',name) } getName(); ( async function(){ const person=await '七個小矮人' //await Promise.resolve('七個小矮人') await後面不跟Promise,也會被封裝成Promise console.log('person:',person)//400 })();//自執行函數 //name: 白雪公主 //person: 七個小矮人
當函數執行的時候,一旦遇到await就會先返回,等到非同步操作完成,再接著執行函數體內後面的語句。任何一個await語句後面的 Promise 物件變為reject狀態,那麼整個async函數都會中斷執行。
async function testOrder() { await Promise.reject('出錯了')//UnhandledPromiseRejectionWarning: 出錯了 await Promise.resolve('hello world'); // 不會執行 } testOrder();
如果希望即使前一個非同步操作失敗,也不要中斷後面的非同步操作。可將第一個await放在try...catch結構裡面,這樣不管這個非同步操作是否成功,第二個await都會執行。
// try...catch !(async function () { const testError = Promise.reject('出錯啦~~~')//rejected狀態 // const testError=throw new Error('出錯啦~~~'); try { const result = await testError; //await相當於then,但是reject不會觸發then console.log('success:'+result) //不會輸出,因為const result = await testError被報錯,被catch捕獲 } catch (error) { console.error('error:'+error)//try...catch 相當於Promise的catch } })() //error:出錯啦~~~
當await後面是Promise物件的時候,我們也可直接在await後面直接.catch捕獲錯誤:
async function testError() { await Promise.reject('出錯了') .catch(error => console.log(error));//這裡捕獲錯誤,不會影響下一個await執行 return await Promise.resolve('hello world'); } testError() .then(result => console.log(result))
我們淺淺看一個面試題:
// 面試題 function getJSON() { return new Promise((resolve, reject) => { setTimeout(() => { console.log(2); resolve(2) }, 2000) }) } async function testAsync() { await getJSON() console.log(3); } testAsync() //2 //3
問題當然不會問列印順序啦,問題是將async await語句解析翻譯為Promise?
根據現在的知識面,我們必須知道:
(1)await不能單獨出現,其函數前面一定要有async。
(2)await會幹兩件事:
第一,將寫在await後面的程式碼放到async建立的那個Promise裡面執行。
第二、將寫在await下面的程式碼放到前一個建立的那個Promise物件的.then裡面執行。
(3)await返回的也是Promise物件,他只是把await下面的程式碼放到了await返回的promise的.then裡面執行。
這樣的話,是不是如魚得水了。翻譯如下:
function getJSON() { return new Promise((resolve, reject) => { setTimeout(() => { console.log(2); resolve(2) }, 2000) }) } // 編譯成Promise原理 function testAsync() { return Promise.resolve().then(() => { return getJSON(); }) .then(() => { console.log(3); }) } testAsync()
你學廢async-await了嘛?還記得上一篇開篇的回撥地獄嘛?我們通過Promise解決回撥是這樣的:
// Promise解決方式 function doCallback(n) { var myPromise = new Promise(function (resolve, reject) { //處理非同步任務 var flag = true; setTimeout(function () { if (flag) { resolve(n) } else { reject('失敗') } },0) }) return myPromise; } doCallback(1) .then((result) => { //then是成功執行的方法 返回的還是一個Promise物件 console.log(result);//列印張三 res是執行 return fn(2); }) .then((result) => { console.log(result); return fn(3) }) .then((result) => { console.log(result); return fn(4) }) .then((result) => { console.log(result); }) .catch((result) => { //catch是失敗執行的方法 console.log(result); }) //好多.then,形成.then鏈啦 //1 //2 //3 //4
通過以上Promise方法,可以明顯解決回撥地獄“向右移”的浮誇表現,但是,Promise是基於 then, catch 的鏈式呼叫,但也是基於回撥函數。.then鏈多多少少還是違背原生程式碼,顯得也不是很優雅。作為回撥終極武器,async-await更加貼近於原生程式碼,我們看一下吧:
//封裝一個返回promise的非同步任務 function doCallback(str) { var myPromise = new Promise(function (resolve, reject) { var flag = true; setTimeout(function () { if (flag) { resolve(str) } else { reject('處理失敗') } }) }) return myPromise; } //封裝一個執行上述非同步任務的async函數 async function testAsync() { var result1 = await doCallback(1); //await直接拿到fn()返回的promise的資料,並且賦值給result var result2 = await doCallback(2); //await 後面的程式碼,都可以看做是非同步回撥 callback 裡的內容,都是非同步的 var result3 = await doCallback(3); var result4 = await doCallback(4); console.log(result1); console.log(result2); console.log(result3); console.log(result4); }//這樣是不是簡潔優雅多了呢? //執行函數 testAsync(); //1 //2 //3 //4
有了 async-await、promise 還有必要學習嗎?通過上面async-await的解決方案可以瞧見,async / await 和 Promise 並不互斥,二者相輔相成。同時async / await 並不能改變非同步的本質( js是單執行緒的,非同步需要回撥,都是要基於 event loop 來實現(什麼是event loop?關注我,等我文章~))。
現在知道了,async-await是promise的語法糖了吧,不僅讓我們書寫程式碼時更加流暢,而且增強了程式碼的可讀性。特別注意的是:雖然async-await 是建立在 Promise機制之上的,但是並不能取代其地位,他們兩者相輔相成,息息相關。
其實async-await不止是Promise的語法糖,還是Generator的語法糖,Generator是什麼?更多關於async-await消滅非同步回撥的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45