狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

JavaScript 異步:Generator與async/await

freeflydom
2024年8月7日 10:32 本文熱度 1886

Generator函數(shù)是ES6提供的一種異步編程解決方案,語法行為與傳統(tǒng)函數(shù)完全不同

前面的文章里我們介紹了回調(diào)函數(shù)promise 這兩種手段來解決異步,本文將繼續(xù)介紹異步發(fā)展史上的另外兩種方法:Generatorasync/await


Generater

執(zhí)行 Generator 函數(shù)會返回一個(gè)遍歷器對象,也就是說,Generator 函數(shù)除了狀態(tài)機(jī),還是一個(gè)遍歷器對象生成函數(shù)。返回的遍歷器對象,可以依次遍歷 Generator 函數(shù)內(nèi)部的每一個(gè)狀態(tài)。

形式上,Generator 函數(shù)是一個(gè)普通函數(shù),但是有兩個(gè)特征。一是,function關(guān)鍵字與函數(shù)名之間有一個(gè)星號;二是,函數(shù)體內(nèi)部使用yield表達(dá)式,定義不同的內(nèi)部狀態(tài)(yield在英語里的意思就是“產(chǎn)出”)

關(guān)鍵特性:

  1. 聲明方式: Generator函數(shù)使用function*語法聲明,星號(*)緊跟著function關(guān)鍵字后面。

  2. Yield表達(dá)式yield表達(dá)式用于暫停和恢復(fù)函數(shù)的執(zhí)行。每次函數(shù)在yield處暫停時(shí),它會返回yield后面的值給調(diào)用者。當(dāng)再次調(diào)用生成器的next()方法時(shí),函數(shù)會從上一個(gè)yield表達(dá)式之后的位置繼續(xù)執(zhí)行,直到下一個(gè)yield或函數(shù)結(jié)束。

  3. 返回遍歷器對象: 執(zhí)行Generator函數(shù)時(shí),它不立即執(zhí)行函數(shù)體內(nèi)的代碼,而是返回一個(gè)遍歷器對象(iterator object)。這個(gè)對象具有next()方法,每次調(diào)用next()方法都會執(zhí)行函數(shù)直到下一個(gè)yield表達(dá)式,或者直到函數(shù)結(jié)束。

  4. 遍歷器協(xié)議: 遍歷器對象遵循遍歷器協(xié)議,next()方法返回一個(gè)對象,該對象有valuedone兩個(gè)屬性。valueyield表達(dá)式的結(jié)果,done是一個(gè)布爾值,表示是否到達(dá)了生成器函數(shù)的末尾。

函數(shù)定義:

Generator函數(shù)的定義與普通函數(shù)類似,但是有以下幾點(diǎn)不同:

  • 函數(shù)聲明前面需要加上星號*,表明這是一個(gè)Generator函數(shù)。

  • 函數(shù)體內(nèi)可以使用yield表達(dá)式來“產(chǎn)出”一系列的值。yield表達(dá)式的作用類似于return,但不會結(jié)束函數(shù),而是暫時(shí)掛起函數(shù)的執(zhí)行,并在下次調(diào)用時(shí)從暫停的地方繼續(xù)執(zhí)行。

使用方法:

  1. 創(chuàng)建Generator對象:調(diào)用Generator函數(shù)時(shí),它不會立即執(zhí)行函數(shù)體內(nèi)的代碼,而是返回一個(gè)Generator對象。這個(gè)對象實(shí)現(xiàn)了迭代器協(xié)議,擁有next()方法。

因?yàn)榇藢ο蠓祷?code>Iterator對象,所以我們可以通過for...of進(jìn)行遍歷

function* hai(){

  yield '嗨!';

  yield '你好嗎?';

  yield '我很好!';

}

for (let h of hai()) {

  console.log(h);

}

  1. next()方法:調(diào)用Generator對象的next()方法會執(zhí)行Generator函數(shù)直到遇到下一個(gè)yield表達(dá)式,或者直到函數(shù)結(jié)束。next()方法返回一個(gè)對象,該對象有兩個(gè)屬性:

    • valueyield表達(dá)式產(chǎn)生的值,如果沒有更多的yield表達(dá)式,則為undefinedyield本身沒有返回值,所以返回undefined)。

    • done:一個(gè)布爾值,表示是否到達(dá)了Generator函數(shù)的末尾。

運(yùn)行邏輯:

  • 遇到yield表達(dá)式,就暫停執(zhí)行后面的操作,并緊緊跟在yield后面的那個(gè)表達(dá)式的值,作為返回對象的value屬性值。

  • 下次調(diào)用next方法時(shí),再繼續(xù)往下執(zhí)行,直到遇到下一個(gè)yield表達(dá)式

  • 如果沒有再遇到新的yield方法,就一直運(yùn)行到函數(shù)結(jié)束,直到return語句為止,并將return語句后面的表達(dá)式的值,作為返回對象的value

  • 如果該函數(shù)沒有return語句,則返回的對象value屬性值為undefind

function* hai(){

  yield '嗨!';

  yield '你好嗎?';

  yield '我很好!';

}


var h = hai();


h.next()

h.next()

h.next()

h.next()

  1. 發(fā)送值給Generator函數(shù)next()方法還可以接受一個(gè)參數(shù),這個(gè)參數(shù)將作為上一個(gè)yield表達(dá)式的值,從而可以向Generator函數(shù)內(nèi)部發(fā)送數(shù)據(jù)。

function* foo(x) {

  var y = 2 * (yield (x + 1));

  var z = yield (y / 3);

  return (x + y + z);

}


var a = foo(5);

a.next()//{value: 6, done: false}    

a.next()//{value: NaN, done: false}

a.next()//value: NaN, done: true}


var b = foo(5);

b.next()//{value: 6, done: false}

b.next(12)//{value: 8, done: false}

b.next(13)//{value: 42, done: true}

a.next()

  • 第一次

  1. foo 函數(shù)開始執(zhí)行,遇到第一個(gè) yield 表達(dá)式 (x + 1),計(jì)算 x + 1 的值,即 5 + 1 = 6

  2. 6 被作為 a.next() 的 value 屬性返回,done 屬性為 false 表示生成器還沒有執(zhí)行完畢。

  • 第二次

  1. foo 函數(shù)繼續(xù)執(zhí)行,遇到 var y = 2 * (yield (x + 1));,由于上一個(gè) yield 表達(dá)式的值被忽略了(沒有通過 a.next(value) 提供),因此 y 的值是 2 * NaN = NaN

  2. 接下來遇到 var z =  yield (y / 3);,返回 y / 3 的值,即 NaN / 3 = NaN

  3. NaN 被作為 a.next() 的 value 屬性返回,done 屬性為 false 表示生成器還沒有執(zhí)行完畢

  • 第三次

  1. foo 函數(shù)繼續(xù)執(zhí)行,遇到 return (x + y + z);,計(jì)算 x + y + z 的值,即 5 + NaN + NaN = NaN

  2. NaN 被作為 a.next() 的 value 屬性返回,done 屬性為 true 表示生成器已經(jīng)執(zhí)行完畢。

b.next()

  • 第一次

  1. foo執(zhí)行,遇到第一個(gè) yield 表達(dá)式 (x + 1),計(jì)算 x + 1 的值,即 5 + 1 = 6

  2. 6 被作為 b.next() 的 value 屬性返回,done 屬性為 false 表示生成器還沒有執(zhí)行完畢。

  • 第二次

  1. 遇到 var y = 2 * (yield (x + 1));,由于上一個(gè) yield 表達(dá)式的值被設(shè)置為 12,因此 y 的值是 2 * 12 = 24

  2. 接下來遇到 var z = y / 3;,計(jì)算 y / 3 的值,即 24 / 3 = 8

  3. 8 被作為 b.next() 的 value 屬性返回,done 屬性為 false 表示生成器還沒有執(zhí)行完畢。

  • 第三次

  1. 這一行代碼執(zhí)行后,foo 函數(shù)繼續(xù)執(zhí)行,遇到 yield (z);,由于上一個(gè) yield 表達(dá)式的值被設(shè)置為 13,但這里 13 不會被使用。

  2. 接下來遇到 return (x + y + z);,計(jì)算 x + y + z 的值,即 5 + 24 + 8 = 37

  3. 37 被作為 b.next() 的 value 屬性返回,done 屬性為 true 表示生成器已經(jīng)執(zhí)行完畢。

示例

代碼高亮:

function* countUpTo(max) {

  for (let i = 1; i <= max; i++) {

    yield i;

  }

}

const counter = countUpTo(3);

// 第一次調(diào)用next(),從1開始

console.log(counter.next()); // { value: 1, done: false }

// 第二次調(diào)用next(),輸出2

console.log(counter.next()); // { value: 2, done: false }

// 最后一次調(diào)用next(),輸出3

console.log(counter.next()); // { value: 3, done: false }

// 再次調(diào)用next(),Generator函數(shù)已經(jīng)結(jié)束

console.log(counter.next()); // { value: undefined, done: true }

async/await

  • async/await是基于Promise的一種更高級的異步編程語法糖。

  • async函數(shù)總是返回一個(gè)Promise。

  • await關(guān)鍵字只能在async函數(shù)內(nèi)部使用,用于等待Promise解析。

  • 使用await關(guān)鍵字可以讓異步代碼看起來和同步代碼非常相似,極大地提高了可讀性和可維護(hù)性。

  • async/await是目前處理異步操作最推薦的方式,因?yàn)樗啙嵡乙子诶斫狻?/p>

使用方法

async/await形式簡潔,直接在函數(shù)前加上async然后在需要異步的操作前加上await即可

下面是使用 async/await 的基本步驟和示例:

步驟

  1. 定義異步函數(shù):

    • 使用 async 關(guān)鍵字定義函數(shù)。

    • 這個(gè)函數(shù)自動返回一個(gè) Promise

  2. 使用 await 關(guān)鍵字:

    • 在 async 函數(shù)內(nèi)部,你可以使用 await 關(guān)鍵字等待一個(gè) Promise 完成。

    • await 只能在 async 函數(shù)內(nèi)部使用。

    • 當(dāng) await 一個(gè) Promise 時(shí),函數(shù)會暫停執(zhí)行,直到 Promise 解析(resolve)或拒絕(reject)。

    • 如果 Promise 成功解析,await 表達(dá)式的值就是 resolve 的值;如果 Promise 被拒絕,則會拋出一個(gè)錯(cuò)誤。

示例

假設(shè)我們有一個(gè)異步函數(shù) getData 用于從服務(wù)器獲取數(shù)據(jù),然后我們使用 async/await 來處理這個(gè)異步操作。

Step 1: 定義數(shù)據(jù)獲取函數(shù)

function getData() {

  return new Promise((resolve) => {

    setTimeout(() => {

      resolve('Hello from server!');

    }, 2000); // 模擬網(wǎng)絡(luò)延遲

  });

}

Step 2: 使用 async/await 獲取數(shù)據(jù)

async function a() {

  console.log(1);

  const data = await getData(); // 等待數(shù)據(jù)獲取完成

  console.log(2);

  console.log(data);

}


// 調(diào)用異步函數(shù)

a();

解釋

  1. 定義異步函數(shù):

    • 使用 async 關(guān)鍵字定義了一個(gè)函數(shù) a

    • 這個(gè)函數(shù)自動返回一個(gè) Promise

  2. 使用 await 關(guān)鍵字:

    • 在 async 函數(shù)內(nèi)部,我們使用 await 關(guān)鍵字等待 getData() 函數(shù)返回的 Promise 完成。

    • await 只能在 async 函數(shù)內(nèi)部使用。

    • 當(dāng) await 一個(gè) Promise 時(shí),函數(shù)會暫停執(zhí)行,直到 Promise 解析(resolve)或拒絕(reject)。

    • 如果 Promise 成功解析,await 表達(dá)式的值就是 resolve 的值;如果 Promise 被拒絕,則會拋出一個(gè)錯(cuò)誤。

  3. 調(diào)用異步函數(shù):

    • 最后,我們可以通過簡單地調(diào)用 a() 來啟動整個(gè)流程。

    • 由于 a 返回一個(gè) Promise,可以通過 .then() 或 .catch() 方法來處理它的結(jié)果或錯(cuò)誤。

運(yùn)行示例

當(dāng)運(yùn)行這個(gè)示例時(shí),會看到以下輸出:

Hello from server!

這是因?yàn)椋?/p>

  • 函數(shù) a() 首先打印數(shù)字 1

  • 然后等待 getData() 返回的數(shù)據(jù),該數(shù)據(jù)將在 2 秒后可用。

  • 當(dāng)數(shù)據(jù)準(zhǔn)備好時(shí),a() 函數(shù)繼續(xù)執(zhí)行,打印數(shù)字 2 和獲取到的數(shù)據(jù) 'Hello from server!'

異步解決方案的區(qū)別

  • promise和async/await是專門用于處理異步操作的

  • Generator 并不是為異步而設(shè)計(jì)出來的,它還有其他功能(對象迭代、控制輸出、部署Interator接口等)

  • promise編碼相比Generator、async更為復(fù)雜化,且可讀性也稍差

  • Generator、async需要與promise對象搭配處理異步情況

  • async實(shí)質(zhì)上是Generator的語法糖,相當(dāng)于會自動執(zhí)行的Generator函數(shù)

  • async使用上更為簡潔,將異步代碼以同步形式進(jìn)行編寫,是處理異步編程的最終方案


以上就是本文全部內(nèi)容,希望對你有所幫助,感謝你的閱讀!

來源:https://juejin.cn/post/7399986436349231144 作者:Alo365


該文章在 2024/8/7 10:32:12 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved