国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

ES7中利用Await減少回調嵌套的方法詳解

2019-11-19 15:00:55
字體:
來源:轉載
供稿:網友

前言

我們知道javascript是沒辦法阻塞的,所有的等待只能通過回調來完成,這就造成了回調嵌套的問題,導致代碼亂到爆,這時候Await就有用處了。

對于await的底層機制這里就不詳述了,以免將文章的篇幅拖的很長,需要的朋友們可以參考這篇文章://m.survivalescaperooms.com/article/123257.htm,下面開始本文的正式內容。

利用Await減少回調嵌套

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

如下代碼所示:

ajax({ url: "/list", type: "GET", success: function(data) { appendToDOM(data); ajax({ url: "/update", type: "POST", success: function(data) { util.toast("Success!"); }) }); }});

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

new Promise(resolve => { ajax({ url: "/list", type: "GET", success: data => resolve(data); })}).then(data => { appendToDOM(data); ajax({ url: "/update", type: "POST", success: function(data) { util.toast("Successfully!"); })  }); });

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

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

let orderPromise = new Promise(resolve => { ajax("/order", "GET", data => resolve(data));});let userPromise = new Promise(resolve => { ajax("/user", "GET", data => resolve(data));});Promise.all([orderPromise, userPromise]).then(values => { let order = values[0], user = values[1];});

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

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

// 使用await獲取異步數據let leadList = await new Promise(resolve => { ajax({ url: "/list", type: "GET", success: data => resolve(data); });});// await讓代碼很自然地像瀑布流一樣寫下來 appendToDom(leadList);ajax({ url: "/update", type: "POST", success: () => util.toast("Successfully");});

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

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

let order = await new Promise( resolve => ajax("/order", data => resovle(data))), user = await new Promise( resolve => ajax("/user", data => resolve(data)));// do sth. with order/user

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

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

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

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

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

let quoteHandler = { confirmCreate: function(){ dialog.showDialog({ contentTpl: tpl, className: "confirm-create-quote" }); let $quoteDialog = $(".confirm-create-quote form")[0]; return new Promise(resolve => { $(form.submit).on("click", function(event){ resolve(form.createType.value); }); }); }}

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

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

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

(1)安裝一個Node包

npm install --save-dev babel-plugin-transform-async-to-generator

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

{ "plugins": ["transform-async-to-generator"]}

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

require("babel-polyfill");

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

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

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

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

function sleep (time) { return new Promise(resolve =>  setTimeout(() => resolve(), time));}async function start () { await sleep(1000);}start();

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

while (1) { switch (_context.prev = _context.next) { case 0: _context.next = 2; // sleep返回一個Promise對象 return sleep(1000); case 2: case "end":  return _context.stop(); }}

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

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

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

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

let quoteHandler = { confirmCreate: function(){ $(form.submit).on("click", function(event){ // 這里會拋undefined異常:訪問了undefined的value屬性 callback(form.notFoundInput.value); }); }}try { // 這里無法捕獲到異常 quoteHandler.confirmCreate();} catch (e) {}

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

let quoteHandler = { confirmCreate: function(){ return new Promise(resolve => { $(form.submit).on("click", function(event){ // 這里會拋undefined異常:訪問了undefined的value屬性 resolve(form.notFoundInput.value); }); }); }}quoteHandler.confirmCreate().then(createType => {}).catch(e => { // 這里能捕獲異常});

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

try { createType = await quoteHandler.confirmCreate("order");}catch(e){ console.log(e); return;}

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

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 临西县| 甘泉县| 晋州市| 广宗县| 贵德县| 乡宁县| 大化| 宾川县| 金塔县| 肥东县| 涪陵区| 象州县| 五大连池市| 扶风县| 南汇区| 白山市| 安顺市| 乌审旗| 宣汉县| 秦皇岛市| 乌兰浩特市| 长治市| 漳平市| 景洪市| 灵川县| 蒙山县| 漯河市| 广丰县| 玉门市| 邵东县| 泾阳县| 鄢陵县| 寿阳县| 新化县| 武川县| 肇东市| 西丰县| 达拉特旗| 泰和县| 公主岭市| 泰和县|