成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何使用Await減少回調嵌套

開發 開發工具
Promise提供了一個resolve,方便通知什么時候異步結束了,不過本質還是一樣的,還是使用回調,只是這個回調放在了then里面。

 [[210217]]

在開發的時候,有時候需要發很多請求,然后經常會面臨嵌套回調的問題,即在一個回調里面又嵌了一個回調,導致代碼層層縮進得很厲害,如下代碼所示:

  1. ajax({ 
  2.     url: "/list"
  3.     type: "GET"
  4.     success: function(data) { 
  5.        appendToDOM(data); 
  6.         ajax({ 
  7.             url: "/update"
  8.             type: "POST"
  9.             success: function(data) { 
  10.                 util.toast("Success!"); 
  11.             }) 
  12.         }); 
  13.     } 
  14. }); 

這樣的代碼看起來有點吃力,這種異步回調通常可以用Promise優化一下,可以把上面代碼改成:

  1. new Promise(resolve => { 
  2.     ajax({ 
  3.         url: "/list"
  4.         type: "GET"
  5.         success: data => resolve(data); 
  6.     }) 
  7. }).then(data => { 
  8.    appendToDOM(data); 
  9.     ajax({ 
  10.         url: "/update"
  11.         type: "POST"
  12.         success: function(data) { 
  13.             util.toast("Successfully!"); 
  14.         })   
  15.     });  
  16. }); 

Promise提供了一個resolve,方便通知什么時候異步結束了,不過本質還是一樣的,還是使用回調,只是這個回調放在了then里面。

當需要獲取多次異步數據的時候,可以使用Promise.all解決:

  1. let orderPromise = new Promise(resolve => { 
  2.     ajax("/order""GET", data => resolve(data)); 
  3. }); 
  4. let userPromise = new Promise(resolve => { 
  5.     ajax("/user""GET", data => resolve(data)); 
  6. }); 
  7.   
  8. Promise.all([orderPromise, userPromise]).then(values => { 
  9.     let order = values[0], 
  10.          user = values[1]; 
  11. }); 

但是這里也是使用了回調,有沒有比較優雅的解決方式呢?

ES7的await/async可以讓異步回調的寫法跟寫同步代碼一樣。***個嵌套回調的例子可以用await改成下面的代碼:

  1. // 使用await獲取異步數據 
  2. let leadList = await new Promise(resolve => { 
  3.     ajax({ 
  4.         url: "/list"
  5.         type: "GET"
  6.         success: data => resolve(data); 
  7.     }); 
  8. }); 
  9.   
  10. // await讓代碼很自然地像瀑布流一樣寫下來  
  11. appendToDom(leadList); 
  12. ajax({ 
  13.     url: "/update"
  14.     type: "POST"
  15.     success: () => util.toast("Successfully"); 
  16. }); 

Await讓代碼可以像瀑布流一樣很自然地寫下來。

第二個例子:獲取多次異步數據,可以改成這樣:

  1. let order = await new Promise( 
  2.            resolve => ajax("/order", data => resovle(data))), 
  3.   
  4.     user = await new Promise( 
  5.            resolve => ajax("/user", data => resolve(data))); 
  6.   
  7. // do sth. with order/user 

這種寫法就好像從本地獲取數據一樣,就不用套回調函數了。

Await除了用在發請求之外,還適用于其它異步場景,例如我在創建訂單前先彈一個小框詢問用戶是要創建哪種類型的訂單,然后再彈具體的設置訂單的框,所以按正常思路這里需要傳遞一個按鈕回調的點擊函數,如下圖所示:

 

但其實可以使用await解決,如下代碼所示:

  1. let quoteHandler = require("./quote"); 
  2. // 彈出框詢問用戶并得到用戶的選擇 
  3. let createType = await quoteHandler.confirmCreate(); 

quote里面返回一個Promise,監聽點擊事件,并傳遞createType:

  1. let quoteHandler = { 
  2.     confirmCreate: function(){ 
  3.         dialog.showDialog({ 
  4.             contentTpl: tpl, 
  5.             className: "confirm-create-quote" 
  6.         }); 
  7.         let $quoteDialog = $(".confirm-create-quote form")[0]; 
  8.         return new Promise(resolve => { 
  9.             $(form.submit).on("click"function(event){ 
  10.                 resolve(form.createType.value); 
  11.             }); 
  12.         }); 
  13.     } 
  14.   

這樣外部調用者就可以使用await,而不用傳遞一個點擊事件的回調函數了。

但是需要注意的是await的一次性執行特點。相對于回調函數來說,await的執行是一次性的,例如監聽點擊事件,然后使用await,那么點擊事件只會執行一次,因為代碼從上往下執行完了,所以當希望點擊之后出錯了還能繼續修改和提交就不能使用await,另外使用await獲取異步數據,如果出錯了,那么成功的resolve就不會執行,后續的代碼也不會執行,所以請求出錯的時候基本邏輯不會有問題。

要在babel里面使用await,需要:

(1)安裝一個Node包

  1. npm install –save-dev babel-plugin-transform-async-to-generator 

(2)在工程的根目錄添加一個.babelrc文件,內容為:

  1.   "plugins": ["transform-async-to-generator"

(3)使用的時候先引入一個模塊

  1. require("babel-polyfill"); 

然后就可以愉快地使用ES7的await了。

使用await的函數前面需要加上async關鍵字,如下代碼:

  1. async showOrderDialog() { 
  2.      // 獲取創建類型 
  3.      let createType = await quoteHandler.confirmCreate(); 
  4.   
  5.      // 獲取老訂單數據  
  6.      let orderInfo = await orderHandler.getOrderData(); 

我們再舉一個例子:使用await實現JS版的sleep函數,因為原生是沒有提供線程休眠函數的,如下代碼所示:

  1. function sleep (time) { 
  2.     return new Promise(resolve =>  
  3.                           setTimeout(() => resolve(), time)); 
  4.   
  5. async function start () { 
  6.     await sleep(1000); 
  7.   
  8. start(); 

babel的await實現是轉成了ES6的generator,如下關鍵代碼:

  1. while (1) { 
  2.     switch (_context.prev = _context.next) { 
  3.         case 0: 
  4.             _context.next = 2; 
  5.             // sleep返回一個Promise對象 
  6.             return sleep(1000); 
  7.   
  8.         case 2: 
  9.         case "end":      
  10.             return _context.stop(); 
  11.     } 

而babel的generator也是要用ES5實現的,什么是generator呢?如下圖所示:

 

生成器用function*定義,每次執行生成器的next函數的時候會返回當前生成器里用yield返回的值,然后生成器的迭代器往后走一步,直到所有yield完了。

有興趣的可以繼續研究babel是如何把ES7轉成ES5的,據說原生的實現還是直接基于Promise.

使用await還有一個好處,可以直接try-catch捕獲異步過程拋出的異常,因為我們是不能直接捕獲異步回調里面的異常的,如下代碼:

  1. let quoteHandler = { 
  2.     confirmCreate: function(){ 
  3.         $(form.submit).on("click"function(event){ 
  4.             // 這里會拋undefined異常:訪問了undefined的value屬性 
  5.             callback(form.notFoundInput.value); 
  6.         }); 
  7.     } 
  8.   
  9. try { 
  10.     // 這里無法捕獲到異常 
  11.     quoteHandler.confirmCreate(); 
  12. } catch (e) { 
  13.   

上面的try-catch是沒有辦法捕獲到異常的,因為try里的代碼已經執行完了,在它執行的過程中并沒有異常,因此無法在這里捕獲,如果使用Promise的話一般是使用Promise鏈的catch:

  1. let quoteHandler = { 
  2.     confirmCreate: function(){ 
  3.         return new Promise(resolve => { 
  4.             $(form.submit).on("click"function(event){ 
  5.                 // 這里會拋undefined異常:訪問了undefined的value屬性 
  6.                 resolve(form.notFoundInput.value); 
  7.             }); 
  8.         }); 
  9.     } 
  10.   
  11. quoteHandler.confirmCreate().then(createType => { 
  12.   
  13. }).catch(e => { 
  14.     // 這里能捕獲異常 
  15. }); 

而使用await,我們可以直接用同步的catch,就好像它真的變成同步執行了:

  1. try { 
  2.     createType = await quoteHandler.confirmCreate("order"); 
  3. }catch(e){ 
  4.     console.log(e); 
  5.     return

總之使用await讓代碼少寫了很多嵌套,很方便的邏輯處理,縱享絲滑。

原文鏈接:https://fed.renren.com/2017/10/31/await/

【本文是51CTO專欄作者“人人網FED”的原創稿件,轉載請通過51CTO聯系原作者獲取授權】

戳這里,看該作者更多好文

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2021-06-07 09:44:10

JavaScript開發代碼

2009-12-22 19:00:08

WCF回調

2011-05-20 17:19:25

回調函數

2009-11-16 17:15:12

Oracle減少回滾段

2009-08-19 17:10:09

C#回調函數

2021-12-27 10:13:51

Goatomic數據競爭

2009-11-09 15:58:07

WCF回調方法

2024-11-25 07:00:00

箭頭函數JavaScriptReact

2023-08-01 07:27:42

Mockito測試Callback

2010-03-01 15:12:53

WCF回調契約

2012-02-01 10:33:59

Java

2013-04-12 09:57:37

CSSJavaScript

2012-07-22 15:59:42

Silverlight

2021-03-10 09:20:31

await代碼前端

2009-08-19 16:40:35

C#回調

2009-08-21 17:02:20

ASP.NET異步回調

2009-08-12 10:11:18

C# 回調函數

2023-11-10 16:31:31

2015-10-26 09:25:42

2019-11-05 10:03:08

callback回調函數javascript
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: www久久久| 国产91丝袜在线18 | 亚洲综合区 | 仙人掌旅馆在线观看 | 色天天综合| 中文字幕成人 | 91成人小视频 | 亚洲视频欧美视频 | 亚洲精品久久久久久一区二区 | 亚洲黄色网址视频 | 97精品超碰一区二区三区 | 81精品国产乱码久久久久久 | 黄色激情毛片 | 高清一区二区 | 久久久日韩精品一区二区三区 | 久久久不卡网国产精品一区 | 日韩精品一区二区三区免费视频 | 秋霞电影院午夜伦 | 久久99蜜桃综合影院免费观看 | 99久久99热这里只有精品 | 亚洲成人一区二区三区 | 日屁视频 | 免费午夜剧场 | 日日操视频| 一级黄色片免费在线观看 | 日韩精品国产精品 | 色婷婷亚洲一区二区三区 | 日韩在线一区二区三区 | 九九99精品 | 国产成人免费在线观看 | 国产日韩欧美 | 99精品视频免费在线观看 | 精产国产伦理一二三区 | 国产精品一区二区三区在线 | 亚洲人在线观看视频 | 欧美国产精品一区二区三区 | 欧美日韩一区二区三区四区 | 色眯眯视频在线观看 | 久久久久国产 | 国产特级毛片aaaaaa喷潮 | 在线视频中文字幕 |