国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

理解async/await

luodongseu / 888人閱讀

摘要:所謂異步,就是調(diào)用在發(fā)出后,這個調(diào)用就直接返回了,調(diào)用者不會立即得到結(jié)果,但是不會阻塞,可以繼續(xù)執(zhí)行后續(xù)操作,而被調(diào)用者執(zhí)行得到結(jié)果后通過狀態(tài)事件來通知調(diào)用者使用回調(diào)函數(shù)來處理這個結(jié)果。另外狀態(tài)的回調(diào)函數(shù)是可省略的。

首先明確一個問題,為什么 Node.js 需要異步編程?

JavaScript 是單線程的,在發(fā)出一個調(diào)用時,在沒有得到結(jié)果之前,該調(diào)用就不返回,意思就是調(diào)用者主動等待調(diào)用結(jié)果,換句話說,就是必須等待上一個任務(wù)執(zhí)行完才能執(zhí)行下一個任務(wù),這種執(zhí)行模式叫:同步
Node.js 的主要應(yīng)用場景是處理高并發(fā)(單位時間內(nèi)極大的訪問量)和 I/O 密集場景(ps: I/O 操作往往非常耗時,所以異步的關(guān)鍵在于解決 I/O 耗時問題),如果采用同步編程,問題就來了,服務(wù)器處理一個 I/O 請求需要大量的時間,后面的請求都將排隊,造成瀏覽器端的卡頓。異步編程能解決這個問題。
所謂異步,就是調(diào)用在發(fā)出后,這個調(diào)用就直接返回了,調(diào)用者不會立即得到結(jié)果,但是不會阻塞,可以繼續(xù)執(zhí)行后續(xù)操作,而被調(diào)用者執(zhí)行得到結(jié)果后通過狀態(tài)、事件來通知調(diào)用者使用回調(diào)函數(shù)( callback )來處理這個結(jié)果。Node在處理耗時的 I/O 操作時,將其交給其他線程處理,自己繼續(xù)處理其他訪問請求,當(dāng) I/O 操作處理好后就會通過事件通知 Node 用回調(diào)做后續(xù)處理。
有個例子非常好:

你打電話問書店老板有沒有《分布式系統(tǒng)》這本書,如果是同步通信機(jī)制,書店老板會說,你稍等,”我查一下",然后開始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結(jié)果(返回結(jié)果)。而異步通信機(jī)制,書店老板直接告訴你我查一下啊,查好了打電話給你,然后直接掛電話了(不返回結(jié)果)。然后查好了,他會主動打電話給你。在這里老板通過“回電”這種方式來回調(diào)。

下面幾種方式是異步解決方案的進(jìn)化過程:

CallBacks

回調(diào)函數(shù)就是函數(shù)A作為參數(shù)傳遞給函數(shù)B,并且在未來某一個時間被調(diào)用。callback的異步模式最大的問題就是,理解困難加回調(diào)地獄(callback hell),看下面的代碼的執(zhí)行順序:

A();
ajax("url1", function(){
    B();
    ajax("url2", function(){
        C();
    }
    D();
});
E();

其執(zhí)行順序為:A => E => B => D => C,這種執(zhí)行順序的確會讓人頭腦發(fā)昏,另外由于由于多個異步操作之間往往會耦合,只要中間一個操作需要修改,那么它的上層回調(diào)函數(shù)和下層回調(diào)函數(shù)都可能要修改,這就陷入了回調(diào)地獄。而 Promise 對象就很好的解決了異步操作之間的耦合問題,讓我們可以用同步編程的方式去寫異步操作。

Promise

Promise 對象是一個構(gòu)造函數(shù),用來生成promise實例。Promise 代表一個異步操作,有三種狀態(tài):pending,resolved(異步操作成功由 pending 變?yōu)?resolved ),rejected(異步操作失敗由 pending 變?yōu)?rejected ),一旦變?yōu)楹髢煞N狀態(tài)將不會再改變。Promise 對象作為構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù),而這個函數(shù)又接受 resolve reject 兩個函數(shù)做為參數(shù),這兩個函數(shù)是JS內(nèi)置的,無需配置。resolve 函數(shù)在異步操作成功后調(diào)用,將pending狀態(tài)變?yōu)?b>resolved,并將它的參數(shù)傳遞給回調(diào)函數(shù);reject 函數(shù)在異步操作失敗時調(diào)用,將pending狀態(tài)變?yōu)?b>rejected,并將參數(shù)傳遞給回調(diào)函數(shù)。

Promise.prototype.then()

Promise構(gòu)造函數(shù)的原型上有一個then方法,它接受兩個函數(shù)作為參數(shù),分別是 resolved 狀態(tài)和 rejected 狀態(tài)的回調(diào)函數(shù),而這兩個回調(diào)函數(shù)接受的參數(shù)分別是Promise實例中resolve函數(shù)和reject函數(shù)中的參數(shù)。 另外rejected狀態(tài)的回調(diào)函數(shù)是可省略的。

下面是一個使用示例:

const instance = new Promise((resolve, reject) => {
    // 一些異步操作
    if(/*異步操作成功*/) {
      resolve(value);
    } else {
      reject(error);
    }
  }
})
instance.then(value => {
  // do something...
}, error => {
  // do something...
})

注意Promise實例在生成后會立即執(zhí)行,而 then 方法只有在所有同步任務(wù)執(zhí)行完后才會執(zhí)行,看看下面的例子:

const promise = new Promise((resolve, reject) => {
  console.log("async task begins!");
  setTimeout(() => {
    resolve("done, pending -> resolved!");
  }, 1000);
})

promise.then(value => {
  console.log(value);
}) 

console.log("1.please wait");
console.log("2.please wait");
console.log("3.please wait");
// async task begins!
// 1.please wait
// 2.please wait
// 3.please wait
// done, pending -> resolved!

上面的實例可以看出,Promise實例生成后立即執(zhí)行,所以首先輸出 "async task begins!",隨后定義了一個異步操作 setTimeout,1秒后執(zhí)行,所以無需等待,向下執(zhí)行,而then方法指定的回調(diào)函數(shù)要在所有同步任務(wù)執(zhí)行完后才執(zhí)行,所以先輸出了3個"please wait",最后輸出"done, pending -> resolved!"。(此處省略了then方法中的reject回調(diào),一般不在then中做rejected狀態(tài)的處理,而使用catch方法專門處理錯誤,相當(dāng)于.then(null, reject))

鏈?zhǔn)秸{(diào)用 then 方法

then 方法會返回一個新的 Promise 實例,可以分兩種情況來看:

指定返回值是新的 Promise 對象,如return new Promise(...),這種情況沒啥好說的,由于返回的是 Promise,后面顯然可以繼續(xù)調(diào)用then方法。

返回值不是Promise, 如:return 1 這種情況還是會返回一個 Promise,并且這個Promise 立即執(zhí)行回調(diào) resolve(1)。所以仍然可以鏈?zhǔn)秸{(diào)用then方法。(注:如果沒有指定return語句,相當(dāng)于返回了undefined

使用 then 的鏈?zhǔn)綄懛ǎ错樞驅(qū)崿F(xiàn)一系列的異步操作,這樣就可以用同步編程的形式去實現(xiàn)異步操作,來看下面的例子,實現(xiàn)隔兩秒打一次招呼:

function sayHi(name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(name);
    }, 2000)
  })
}

sayHi("張三")
  .then(name => {
    console.log(`你好, ${name}`);
    return sayHi("李四");    // 最終 resolved 函數(shù)中的參數(shù)將作為值傳遞給下一個then
  })
  // name 是上一個then傳遞出來的參數(shù)
  .then(name => {                
    console.log(`你好, ${name}`);
    return sayHi("王二麻子");
  })
  .then(name => {
    console.log(`你好, ${name}`);
  })
// 你好, 張三
// 你好, 李四
// 你好, 王二麻子

可以看到使用鏈?zhǔn)絫hen的寫法,將異步操作變成了同步的形式,但是也帶來了新的問題,就是異步操作變成了很長的then鏈,新的解決方法就是Generator,這里跨過它直接說它的語法糖:async/await

async/await

async

async/await實際上是Generator的語法糖。顧名思義,async關(guān)鍵字代表后面的函數(shù)中有異步操作,await表示等待一個異步方法執(zhí)行完成。聲明異步函數(shù)只需在普通函數(shù)前面加一個關(guān)鍵字async即可,如:

async function funcA() {}

async 函數(shù)返回一個Promise對象(如果指定的返回值不是Promise對象,也返回一個Promise,只不過立即 resolve ,處理方式同 then 方法),因此 async 函數(shù)通過 return 返回的值,會成為 then 方法中回調(diào)函數(shù)的參數(shù):

async function funcA() {
  return "hello!";
}

funcA().then(value => {
  console.log(value);
})
// hello!

多帶帶一個 async 函數(shù),其實與Promise執(zhí)行的功能是一樣的,來看看 await 都干了些啥。

await

顧名思義, await 就是異步等待,它等待的是一個Promise,因此 await 后面應(yīng)該寫一個Promise對象,如果不是Promise對象,那么會被轉(zhuǎn)成一個立即 resolve 的Promise。 async 函數(shù)被調(diào)用后就立即執(zhí)行,但是一旦遇到 await 就會先返回,等到異步操作執(zhí)行完成,再接著執(zhí)行函數(shù)體內(nèi)后面的語句。總結(jié)一下就是:async函數(shù)調(diào)用不會造成代碼的阻塞,但是await會引起async函數(shù)內(nèi)部代碼的阻塞。看看下面這個例子:

async function func() {
  console.log("async function is running!");
  const num1 = await 200;
  console.log(`num1 is ${num1}`);
  const num2 = await num1+ 100;
  console.log(`num2 is ${num2}`);
  const num3 = await num2 + 100;
  console.log(`num3 is ${num3}`);
}

func();
console.log("run me before await!");
// async function is running!
// run me before await!
// num1 is 200
// num2 is 300
// num3 is 400

可以看出調(diào)用 async func 函數(shù)后,它會立即執(zhí)行,首先輸出了"async function is running!",接著遇到了 await 異步等待,函數(shù)返回,先執(zhí)行func()后面的同步任務(wù),同步任務(wù)執(zhí)行完后,接著await等待的位置繼續(xù)往下執(zhí)行。可以說,async函數(shù)完全可以看作多個異步操作,包裝成的一個Promise 對象,而await命令就是內(nèi)部then命令的語法糖。

值得注意的是, await 后面的 Promise 對象不總是返回 resolved 狀態(tài),只要一個 await 后面的Promise狀態(tài)變?yōu)?rejected ,整個 async 函數(shù)都會中斷執(zhí)行,為了保存錯誤的位置和錯誤信息,我們需要用 try...catch 語句來封裝多個 await 過程,如下:

async function func() {
  try {
    const num1 = await 200;
    console.log(`num1 is ${num1}`);
    const num2 = await Promise.reject("num2 is wrong!");
    console.log(`num2 is ${num2}`);
    const num3 = await num2 + 100;
    console.log(`num3 is ${num3}`);
  } catch (error) {
    console.log(error);
  }
}

func();
// num1 is 200
// 出錯了
// num2 is wrong!

如上所示,在 num2 await 得到了一個狀態(tài)為 rejected 的Promise對象,該錯誤會被傳遞到 catch 語句中,這樣我們就可以定位錯誤發(fā)生的位置。

async/await比Promise強(qiáng)在哪兒?

接下來我們用async/await改寫一下Promise章節(jié)中關(guān)于sayHi的一個例子,代碼如下:

function sayHi(name) {
  return new Promise((resolved, rejected) => {
    setTimeout(() => {
      resolved(name);
    }, 2000)
  })
}

async function sayHi_async(name) {
  const sayHi_1 = await sayHi(name)
  console.log(`你好, ${sayHi_1}`)
  const sayHi_2 = await sayHi("李四")
  console.log(`你好, ${sayHi_2}`)
  const sayHi_3 = await sayHi("王二麻子")
  console.log(`你好, ${sayHi_3}`)
}

sayHi_async("張三")
// 你好, 張三
// 你好, 李四
// 你好, 王二麻子

與之前長長的then鏈和then方法里的回調(diào)函數(shù)相比,這樣的寫法看起來像是同步寫法并且更加清爽,更加符合編程習(xí)慣。

參考文章

https://segmentfault.com/a/11...
https://segmentfault.com/a/11...
https://www.zhihu.com/questio...

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/95952.html

相關(guān)文章

  • 8張圖幫你一步步看清 async/await 和 promise 的執(zhí)行順序

    摘要:第部分畫圖一步步看清宏任務(wù)微任務(wù)的執(zhí)行過程我們以開篇的經(jīng)典面試題為例,分析這個例子中的宏任務(wù)和微任務(wù)。注意這里只是把推入微任務(wù)隊列,并沒有執(zhí)行。執(zhí)行結(jié)束,才能繼續(xù)執(zhí)行后面的代碼如圖此時當(dāng)前宏任務(wù)都執(zhí)行完了,要處理微任務(wù)隊列里的代碼。 8張圖讓你一步步看清 async/await 和 promise 的執(zhí)行順序 為什么寫這篇文章? 測試一下自己有沒有必要看 需要具備的前置基礎(chǔ)知識 主...

    weizx 評論0 收藏0
  • 理解 JavaScript 的 async/await

    摘要:因為函數(shù)返回一個對象,所以可以用于等待一個函數(shù)的返回值這也可以說是在等函數(shù),但要清楚,它等的實際是一個返回值。幫我們干了啥作個簡單的比較上面已經(jīng)說明了會將其后的函數(shù)函數(shù)表達(dá)式或的返回值封裝成一個對象,而會等待這個完成,并將其的結(jié)果返回出來。 隨著 Node 7 的發(fā)布,越來越多的人開始研究據(jù)說是異步編程終級解決方案的 async/await。我第一次看到這組關(guān)鍵字并不是在 JavaSc...

    tracymac7 評論0 收藏0
  • promise async await 理解筆記

    摘要:在異步編程中,提供了對象的方式。例如等同于所以可以理解為生成一個實例。那么自然也可以去調(diào)用則是配合使用的。等于是等待一個返回值,等待的執(zhí)行結(jié)果。但是函數(shù)不會造成阻塞,所以配合使用,則沒有影響到外部。 在異步編程中,es6提供了promise對象的方式。簡單的用法 var promise = new Promise((resolve,reject)=>{ if(){ ...

    NoraXie 評論0 收藏0
  • [譯]帶你理解 Async/await

    摘要:所以是在一秒后顯示的。這個行為不會耗費資源,因為引擎可以同時處理其他任務(wù)執(zhí)行其他腳本,處理事件等。每個回調(diào)首先被放入微任務(wù)隊列然后在當(dāng)前代碼執(zhí)行完成后被執(zhí)行。,函數(shù)是異步的,但是會立即運行。否則,就返回結(jié)果,并賦值。 「async/await」是 promises 的另一種更便捷更流行的寫法,同時它也更易于理解和使用。 Async functions 讓我們以 async 這個關(guān)鍵字開...

    xiaochao 評論0 收藏0
  • 令人費解的 async/await 執(zhí)行順序

    摘要:問題的關(guān)鍵在于其執(zhí)行過程中的微任務(wù)數(shù)量,下文中我們需要用上述代碼中的方式對微任務(wù)的執(zhí)行順序進(jìn)行標(biāo)記,以輔助我們理解這其中的執(zhí)行過程。 原文發(fā)布在掘金社區(qū):https://juejin.im/post/5c3cc981f265da616a47e028 起源 2019年了,相信大家對 Promise 和 async/await 都不再陌生了。 前幾日,我在社區(qū)讀到了一篇關(guān)于 async/...

    WilsonLiu95 評論0 收藏0
  • 理解 async/await

    摘要:而函數(shù)的命令后面則可以是或者原始類型的值,,,但這時等同于同步操作返回值是。拋出的錯誤而會被方法回調(diào)函數(shù)接收到。 ES7 提出的async 函數(shù),終于讓 JavaScript 對于異步操作有了終極解決方案。No more callback hell。async 函數(shù)是 Generator 函數(shù)的語法糖。使用 關(guān)鍵字 async 來表示,在函數(shù)內(nèi)部使用 await 來表示異步。想較于 G...

    kid143 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<