亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

以圖表和示例的角度解讀async/await

sutaking / 2458人閱讀

摘要:在中,表示抽象的非阻塞異步執(zhí)行。在完成之后安排代碼的唯一方式是通過(guò)方法綁定回調(diào)函數(shù)。下圖描述了該示例的計(jì)算過(guò)程方法中綁定的回調(diào)函數(shù)只有當(dāng)成功的時(shí)候才會(huì)調(diào)用。為了處理失敗的,需要通過(guò)綁定另一個(gè)回調(diào)函數(shù)。

介紹

ES7中,async/await 語(yǔ)法使異步promise的協(xié)調(diào)變得很簡(jiǎn)單。如果你需要以特定順序異步獲取來(lái)自多個(gè)數(shù)據(jù)庫(kù)或API的數(shù)據(jù),可以使用雜亂的promise或回調(diào)函數(shù)。async/await使我們可以更簡(jiǎn)便地處理這種邏輯,代碼的可讀性和可維護(hù)性也更好。

在該教程中,我們用圖表和一些簡(jiǎn)單的例子來(lái)解釋async/await的語(yǔ)法和語(yǔ)義。
開始講解之前,我們先對(duì)promise進(jìn)行一個(gè)簡(jiǎn)單的概述,如果你對(duì)promise已經(jīng)很熟悉了,可以跳過(guò)該部分內(nèi)容。

Promises

在js中,promise表示抽象的非阻塞異步執(zhí)行。js中的promise與Java中的 Future或C#中的Task很相似。

promise通常用于網(wǎng)絡(luò)和I/O操作-例如,讀取文件,發(fā)起HTTP請(qǐng)求。為了不阻塞當(dāng)前執(zhí)行線程,我們創(chuàng)建一個(gè)異步promise,使用then方法綁定一個(gè)回調(diào)函數(shù),該回調(diào)函數(shù)會(huì)在promise完成后觸發(fā)?;卣{(diào)函數(shù)本身也可以返回一個(gè)promise,所以promise可以高效的鏈?zhǔn)秸{(diào)用。

簡(jiǎn)單起見,所有的例子中我們都假定request-promise庫(kù)已經(jīng)安裝和加載完成了,如下所示:

var rp = require("request-promise");

現(xiàn)在我們可以像這樣發(fā)起一個(gè)簡(jiǎn)單的HTTP GET請(qǐng)求,該方法返回一個(gè)promise:

const promise = rp("http://example.com/")

接下來(lái),看一個(gè)例子:

console.log("Starting Execution");

const promise = rp("http://example.com/");
promise.then(result => console.log(result));

console.log("Can"t know if promise has finished yet...");

在第三行,我們創(chuàng)建了一個(gè)promise,然后我們?cè)诘谒男兄袨槠浣壎艘粋€(gè)回調(diào)函數(shù)。由于promise是異步執(zhí)行的
,所以執(zhí)行到第六行時(shí),我們不確定promise有沒(méi)有完成。多次運(yùn)行上面的代碼,得到的結(jié)果可能每次都不一樣。更通俗地講,promise后面的代碼和promise是并行運(yùn)行的。

在promise完成之前,沒(méi)有辦法中斷當(dāng)前的操作序列。這與Java中的 Future.get是不同的,Future.get允許我們中斷當(dāng)前的線程直到Future完成。js中,我們不會(huì)輕易地等待promise執(zhí)行完成。在promise完成之后安排代碼的唯一方式是通過(guò)then方法綁定回調(diào)函數(shù)。

下圖描述了該示例的計(jì)算過(guò)程:

then方法中綁定的回調(diào)函數(shù)只有當(dāng)promise成功的時(shí)候才會(huì)調(diào)用。如果promise失敗的話(例如,由于網(wǎng)絡(luò)錯(cuò)誤),回調(diào)不會(huì)執(zhí)行。為了處理失敗的promise,需要通過(guò)catch綁定另一個(gè)回調(diào)函數(shù)。

rp("http://example.com/").
    then(() => console.log("Success")).
    catch(e => console.log(`Failed: ${e}`))

最后,為了測(cè)試一下效果,我們通過(guò)Promise.resolvePromise.reject簡(jiǎn)單地生成成功和失敗的promise:

const success = Promise.resolve("Resolved");
// Will print "Successful result: Resolved"
success.
    then(result => console.log(`Successful result: ${result}`)).
    catch(e => console.log(`Failed with: ${e}`))


const fail = Promise.reject("Err");
// Will print "Failed with: Err"
fail.
    then(result => console.log(`Successful result: ${result}`)).
    catch(e => console.log(`Failed with: ${e}`))

有關(guān)promise更詳細(xì)的教程,查看這篇文章

問(wèn)題-組合Promise

單個(gè)promise是很簡(jiǎn)單的??墒?,我們編寫復(fù)雜的異步邏輯時(shí),可能需要組合使用多個(gè)promise來(lái)處理。大量的then語(yǔ)句和匿名回調(diào)函數(shù)很容易讓代碼變得不可維護(hù)。

例如,我們要編寫一個(gè)如下功能的代碼:

發(fā)起一個(gè)HTTP請(qǐng)求,等待完成后,打印出結(jié)果

然后發(fā)起兩個(gè)并行的HTTP請(qǐng)求;

后兩個(gè)請(qǐng)求都完成后,打印出他們的結(jié)果。

下面的代碼片段演示了上述功能的實(shí)現(xiàn):

// Make the first call
const call1Promise = rp("http://example.com/");

call1Promise.then(result1 => {
    // Executes after the first request has finished
    console.log(result1);

    const call2Promise = rp("http://example.com/");
    const call3Promise = rp("http://example.com/");

    return Promise.all([call2Promise, call3Promise]);
}).then(arr => {
    // Executes after both promises have finished
    console.log(arr[0]);
    console.log(arr[1]);
})

首先發(fā)起第一個(gè)HTTP請(qǐng)求,當(dāng)該請(qǐng)求完成后,調(diào)用它的回調(diào)函數(shù)(1-3行)。在回調(diào)函數(shù)中,我們又相繼發(fā)起兩個(gè)HTTP請(qǐng)求生成了兩個(gè)promise。這兩個(gè)promise并行運(yùn)行;當(dāng)他們都執(zhí)行完后,我們還需要為其綁定一個(gè)回調(diào)函數(shù)。因此,我們用promise.all將這兩個(gè)promise組合成一個(gè)promise, 只有當(dāng)他們都完成后,這個(gè)promise才會(huì)完成。由于第一個(gè)回調(diào)函數(shù)的結(jié)果是promise,因此我們鏈?zhǔn)降卣{(diào)用另一個(gè)then方法和回調(diào)函數(shù)輸出最終結(jié)果。

下圖描述了這個(gè)執(zhí)行過(guò)程:

對(duì)于這么簡(jiǎn)單的例子,我們就用了兩個(gè)then回調(diào)和promise.all來(lái)同步并行的promise。試想如果我們執(zhí)行更多的異步操作或者增加錯(cuò)誤處理函數(shù)呢?這種方式很容易讓代碼變成一堆雜亂的then、promise.all和回調(diào)函數(shù)。

Async 函數(shù)

async 函數(shù)提供了一種簡(jiǎn)潔的方式來(lái)定義一個(gè)返回promise的函數(shù)。
例如,下面兩種定義是等價(jià)的:

function f() {
    return Promise.resolve("TEST");
}

// asyncF is equivalent to f!
async function asyncF() {
    return "TEST";
}

相似地,在異步函數(shù)拋出異常與返回一個(gè)reject promise對(duì)象的函數(shù)等價(jià):

function f() {
    return Promise.reject("Error");
}

// asyncF is equivalent to f!
async function asyncF() {
    throw "Error";
}
Await

我們不能同步等待promise的完成。只能通過(guò)then方法傳入一個(gè)回調(diào)函數(shù)。我們鼓勵(lì)非阻塞編程,因此同步等待promise是不允許的。否則,開發(fā)者會(huì)產(chǎn)生編寫同步腳本的想法,畢竟同步編程要簡(jiǎn)單的多。

但是,為了同步promise我們需要允許他們等待彼此的完成。換句話說(shuō),如果操作是異步的(也就是說(shuō)包裹在promise中),它應(yīng)該可以等待其他異步操作的完成。但是,js解析器怎么知道操作是否跑在promise中?

答案是async關(guān)鍵字。每個(gè)async函數(shù)返回一個(gè)promise。因此,js解析器知道所有的操作都位于async函數(shù)中,并將所有的代碼包裹在promise中異步地執(zhí)行。所以,async函數(shù),允許操作等待其他promise的完成。

說(shuō)一下await關(guān)鍵字。它只能用在async函數(shù)中,允許我們同步等待promise的完成。如果在async函數(shù)外邊使用promise,我們?nèi)匀恍枰褂?b>then回調(diào)函數(shù)。

async function f(){
    // response will evaluate as the resolved value of the promise
    const response = await rp("http://example.com/");
    console.log(response);
}

// We can"t use await outside of async function.
// We need to use then callbacks ....
f().then(() => console.log("Finished"));

現(xiàn)在我們看一下前面的那個(gè)例子如何用async/await進(jìn)行改寫:

/ Encapsulate the solution in an async function
async function solution() {
    // Wait for the first HTTP call and print the result
    console.log(await rp("http://example.com/"));

    // Spawn the HTTP calls without waiting for them - run them concurrently
    const call2Promise = rp("http://example.com/");  // Does not wait!
    const call3Promise = rp("http://example.com/");  // Does not wait!

    // After they are both spawn - wait for both of them
    const response2 = await call2Promise;
    const response3 = await call3Promise;

    console.log(response2);
    console.log(response3);
}

// Call the async function
solution().then(() => console.log("Finished"));

以上代碼,我們的解決方案就封裝在了async函數(shù)中。我們可以直接await promise的執(zhí)行,省掉了then回調(diào)函數(shù)。最后,我們只需要調(diào)用async函數(shù)。它封裝了調(diào)用其他promise的邏輯,并返回一個(gè)promise。

實(shí)際上在上面的例子中,promise是并行觸發(fā)的。本例中也一樣(7-8行)。注意第12-13行我們使用了await阻塞主線程,等待所有的promise執(zhí)行完成。后面,我們看到promise都完成了,和前面的例子類似(promise.all(...).then(...))。

其執(zhí)行流程與前例的流程是相等的。但是,代碼變得更具可讀性和簡(jiǎn)潔。

底層實(shí)現(xiàn)上,await/async實(shí)際上轉(zhuǎn)換成了promise,換句話說(shuō),await/async是promise的語(yǔ)法糖。每次我們使用await時(shí),js解析器會(huì)生成一個(gè)promise,并將async函數(shù)中的剩余代碼放到then回調(diào)中去執(zhí)行。
思考下面的例子:

async function f() {
    console.log("Starting F");
    const result = await rp("http://example.com/");
    console.log(result);
}

下面描述函數(shù)f的基本計(jì)算過(guò)程。由于f是異步的,它會(huì)與調(diào)用方并行執(zhí)行:


函數(shù)f開始執(zhí)行,遇到await后生成一個(gè)promise。此時(shí),函數(shù)的其余部分被封裝在回調(diào)中,并在promise完成后執(zhí)行。

錯(cuò)誤處理

前面的大部分例子中,我們都是假設(shè)promise成功完成了。因此,等待promise返回一個(gè)值。如果我們等待的promise失敗了,在async函數(shù)中會(huì)導(dǎo)致一個(gè)異常。我們可以使用標(biāo)準(zhǔn)的try/catch來(lái)捕獲和處理它。

async function f() {
    try {
        const promiseResult = await Promise.reject("Error");
    } catch (e){
        console.log(e);
    }
}

如果async函數(shù)沒(méi)有處理異常,不管是promise reject了,還是產(chǎn)生了其他bug,它都會(huì)返回一個(gè)rejected的promise對(duì)象。

async function f() {
    // Throws an exception
    const promiseResult = await Promise.reject("Error");
}

// Will print "Error"
f().
    then(() => console.log("Success")).
    catch(err => console.log(err))

async function g() {
    throw "Error";
}

// Will print "Error"
g().
    then(() => console.log("Success")).
    catch(err => console.log(err))

這給我們提供了一種簡(jiǎn)便的方法,通過(guò)已知的異常處理機(jī)制來(lái)處理被rejected的promise。

討論

async/await 在語(yǔ)言結(jié)構(gòu)上是對(duì)promise的補(bǔ)充。但是,async/await 并不能取代純promise的需求。例如,在正常函數(shù)和全局作用域我們不能使用await,所以需要使用普通的promise:

async function fAsync() {
    // actual return value is Promise.resolve(5)
    return 5;
}

// can"t call "await fAsync()". Need to use then/catch
fAsync().then(r => console.log(`result is ${r}`));

我通常會(huì)將異步邏輯封裝到一個(gè)或者少數(shù)幾個(gè)async函數(shù)中,然后在非異步代碼中調(diào)用async函數(shù)。這樣我可以最小化降低書寫then/catch的數(shù)量。
學(xué)者們指出,并發(fā)性和并行性是有區(qū)別的。并發(fā)性是指將獨(dú)立的進(jìn)程(一般意義上的進(jìn)程)組合在一起,而并行實(shí)際上是同時(shí)執(zhí)行多個(gè)進(jìn)程。并發(fā)性是關(guān)于應(yīng)用程序設(shè)計(jì)和結(jié)構(gòu)的,而并行性是關(guān)于實(shí)際執(zhí)行的。

我們以一個(gè)多線程應(yīng)用程序?yàn)槔?yīng)用程序分離到線程定義了它的并發(fā)模型。這些線程在可用內(nèi)核上的映射定義了它的級(jí)別或并行性。并發(fā)系統(tǒng)可以在單個(gè)處理器上高效運(yùn)行,在這種情況下,它不是并行的。

就此而言,promise允許我們將一個(gè)程序分解為并行的并發(fā)模塊,也可以不并行運(yùn)行。實(shí)際的JavaScript執(zhí)行是否并行取決于實(shí)現(xiàn)。例如,Node Js是單線程的,如果一個(gè)promise是CPU綁定的,你就不會(huì)看到太多的并行性。然而,如果你通過(guò)像Nashorn這樣的東西把你的代碼編譯成java字節(jié)碼,理論上你可能能夠在不同核心上映射CPU綁定的promise,并且實(shí)現(xiàn)并行性。因此,在我看來(lái),promise(無(wú)論是普通的或通過(guò)await/async)構(gòu)成了JavaScript應(yīng)用程序的并發(fā)模型。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/89634.html

相關(guān)文章

  • 可靠React組件設(shè)計(jì)7個(gè)準(zhǔn)則之SRP

    摘要:編寫組件時(shí)要考慮的基本準(zhǔn)則是單一職責(zé)原則。這些更改通常要求組件在隔離狀態(tài)下易于修改這也是的目標(biāo)。解決多重責(zé)任問(wèn)題需要將分割為兩個(gè)組件和。組件之間的通信是通過(guò)實(shí)現(xiàn)。更改的唯一原因是修改表單字段。 翻譯:劉小夕原文鏈接:https://dmitripavlutin.com/7-... 原文的篇幅非常長(zhǎng),不過(guò)內(nèi)容太過(guò)于吸引我,還是忍不住要翻譯出來(lái)。此篇文章對(duì)編寫可重用和可維護(hù)的React組...

    Charles 評(píng)論0 收藏0
  • 【譯】async/await 應(yīng)知應(yīng)會(huì)

    摘要:原文地址原文作者翻譯作者是在版本中引入的,它對(duì)于中的異步編程而言是一個(gè)巨大的提升??赡軙?huì)產(chǎn)生誤導(dǎo)一些文章把和進(jìn)行了比較,同時(shí)說(shuō)它是異步編程演變過(guò)程中的下一代解決方案,對(duì)此我不敢茍同。結(jié)論在中引入的關(guān)鍵字無(wú)疑是對(duì)異步編程的一大加強(qiáng)。 原文地址: https://hackernoon.com/javasc...原文作者: Charlee Li 翻譯作者: Xixi20160512 asy...

    Ku_Andrew 評(píng)論0 收藏0
  • 黃金搭檔 -- JS 裝飾器(Decorator)與Node.js路由

    摘要:即為裝飾器函數(shù)的這里主要為了獲取路由路徑的前綴,為請(qǐng)求方法,為請(qǐng)求路徑,為請(qǐng)求執(zhí)行的函數(shù)。下邊是設(shè)置路由路徑前綴和塞入內(nèi)容的裝飾器函數(shù)就不多說(shuō)了,就是掛載前綴路徑到類的原型對(duì)象上,這里需要注意的是作用于類,所以是被修飾的類本身。 很多面對(duì)象語(yǔ)言中都有裝飾器(Decorator)函數(shù)的概念,Javascript語(yǔ)言的ES7標(biāo)準(zhǔn)中也提及了Decorator,個(gè)人認(rèn)為裝飾器是和async/a...

    simon_chen 評(píng)論0 收藏0
  • 如何正確合理使用 JavaScript async/await !

    摘要:想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳博客一年百來(lái)篇優(yōu)質(zhì)文章等著你引入的在的異步編程中是一個(gè)極好的改進(jìn)??赡軙?huì)產(chǎn)生誤導(dǎo)一些文章將與進(jìn)行了比較,并聲稱它是下一代異步編程風(fēng)格,對(duì)此作者深表異議。結(jié)論引入的關(guān)鍵字無(wú)疑是對(duì)異步編程的改進(jìn)。 showImg(https://segmentfault.com/img/bVbjFP0?w=800&h=450); 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇...

    trigkit4 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<