摘要:前言終于開始寫了,離這個系列的終結又進了一步。想要看更深度解析的朋友可以移步漫話與異步第三話化異步為同步這里面談及了的底層實現(xiàn)及的用法。用法在我的理解中,最大的特點就是可以讓函數(shù)在特定的地方停下,等待被喚醒后在函數(shù)內部環(huán)境中繼續(xù)執(zhí)行。
前言
終于開始寫generator了,離這個系列的終結又進了一步。其實generator我還處在會用但是不理解原理的狀態(tài),但是知識不總結,不記錄的話容易忘記,所以我還是把現(xiàn)在的一點心得記錄下來。等到以后有了更深的理解再回來補充。
想要看更深度解析generator的朋友可以移步漫話JavaScript與異步·第三話——Generator:化異步為同步這里面談及了generator的底層實現(xiàn)及generator的用法。是我看過的文章中自認為解釋的最好的一篇,而且篇幅也不長,建議大家去看一看。
根據(jù)一貫的作風,我們先嘗試自己實現(xiàn)generator
嘗試ing............
好了嘗試完了,實現(xiàn)不了,老老實實的學習generator的用法吧。
在我的理解中,generator最大的特點就是可以讓函數(shù)在特定的地方停下,等待被喚醒后在函數(shù)內部環(huán)境中繼續(xù)執(zhí)行。我們結合代碼來看一看:
注釋:【1】Iterator Object對象:參考 Iterator 文章比較長,但是如果只是想要了解什么是Iterator Object的話看完第一小節(jié)就足夠了
//輸出分割線的函數(shù),感興趣的可以自行百度如何設置console.log的樣式 function cut_off(color) { console.log("%c------------------------------------------","color:"+color+";font-size:20px"); } //* 為generator函數(shù)的標識,如果我們想要創(chuàng)建一個generator函數(shù)就必須在function后面加上* function* generator() { let num1, num2; num1 = 123; console.log("num1", num1, "num2", num2); //yield就是該函數(shù)內部暫停的地方,暫停的同時會把yield后面的值返回出去 yield num1; num2 = 456; console.log("num1", num1, "num2", num2); yield num2; console.log("num1", num1, "num2", num2); return "end" } console.log("generator defined"); //函數(shù)返回一個Iterator Object對象; // 但是與普通函數(shù)不同的是,這個時候函數(shù)并不執(zhí)行函數(shù)內部的代碼 let g = generator(); console.log("g defined"); cut_off("red"); console.log("g.next() run 1"); //開始執(zhí)行函數(shù)內部的代碼,并且遇在到y(tǒng)ield的時候返回 yield后面的值 console.log(g.next()); cut_off("red"); console.log("g.next() run 2"); //從上次執(zhí)行完的地方執(zhí)行,并且遇在到y(tǒng)ield的時候返回 yield后面的值 console.log(g.next()); cut_off("red"); console.log("g.next() run 3"); //從上次執(zhí)行完的地方執(zhí)行,這次是最后一次有值的返回,done的狀態(tài)會變?yōu)閠rue console.log(g.next()); cut_off("red"); console.log("g.next() run 4"); //已經(jīng)執(zhí)行完成之后再次被調用,永遠返回{value:undefined, done: true} console.log(g.next()); cut_off("red"); console.log("g.next() run 5"); //已經(jīng)執(zhí)行完成之后再次被調用,永遠返回{value:undefined, done: true} console.log(g.next());
貼上一張代碼和運行結果的對比圖輔助大家理解
希望大家看到這里已經(jīng)理解了generator的基本用法,但是這個東西確實有點難,所以我放出聯(lián)系方式
我有空的時候可以一起探討一下
接下來我要講generator最重要的第二個特性,我們可以通過.next(value)為yeild賦值(這是不準確的說法,但是我們可以這么理解,方便我們使用generator),還是貼代碼:
function* generator() { //第一次調用.next()是啟動了這個函數(shù)一直運行到下一個yield的位置 let num1, num2; num1 = 123; console.log("num1", num1, "num2", num2); num2 = yield num1;/*1.由于運算的順序,js會先計算右邊的值,也就是在num2被賦值之前,函數(shù)就停止運行了 2.第二次調用.next(value)的時候,value被next傳入了yield的位置 3.程序繼續(xù)運行,value被賦值給了num2 */ console.log("num1", num1, "num2", num2); return num2 } let g = generator(); console.log("g.next() run 1"); console.log(g.next()); cut_off("red"); console.log("g.next(789) run 2"); //從上次執(zhí)行完的地方執(zhí)行,并且將789傳入函數(shù)內部 console.log(g.next(789));
貼出函數(shù)和運行結果的對比圖,輔助大家理解.next(value)為yeild賦值(該說法并不準確)
generator的基礎學習到這里就能嘗試實際使用了,接下來我們嘗試讓generator在異步中大展身手吧,話不多說上代碼;
//模擬異步請求 let request = function (sucF, errF) { if ((sucF && typeof sucF !== "function") || (errF && typeof errF !== "function")) { throw new Error("傳入?yún)?shù)必須為函數(shù)") } setTimeout(function () { let data = parseInt(Math.random() * 100); if (data < 90 && sucF) { sucF(data) } else if (errF) { errF("本次異步失敗了") } }, 100) }; function* generator() { let num1, num2; num1 = yield request((data) => { g.next(data) //這個地方可能有些難以理解,為什么在g被創(chuàng)建之前,就被使用了。 }, err => { //這個問題可以看注釋【1】來輔助理解 console.error(err); g.return(err) //跳過所有的yield,return直接返回err }); console.log("num1", num1, "num2", num2); num2 = yield request((data) => { g.next(data) }, err => { console.error(err); g.return(err) //跳過所有的yield,return直接返回err }); console.log("num1", num1, "num2", num2); return num2 } let g = generator(); //啟動 g.next();
注釋【1】:為了解釋g為什么可以在被創(chuàng)建之前就‘被調用’
//其實在運行generator的時候generator內部的代碼塊并沒有開始運行,而是返回了一個Iterator對象,所以大家可以這樣簡單理解 //function* generator 相當于 function generator(){ let obj = {}; obj.next=function(){ console.log(g); }; return obj } //這樣在調用generator()的時候,g不會被使用 let g = generator(); //這個時候g被調用了,但是在上一行代碼中,g已經(jīng)被定義了,所以沒有問題,不會報錯 g.next()
這篇文章暫時寫到這里,因為我的頁面開始卡了,所以我把generator和promise結合的用法放到下一篇文章中去;(ps:今天就會寫出來的)
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103633.html
摘要:你能學到什么如何使用實現(xiàn)異步編程異步編程的原理解析前言結合上一篇文章,我們來聊聊基礎原理說到異步編程,你想到的是和,但那也只是的語法糖而已。表示一個異步操作的最終狀態(tài)完成或失敗,以及其返回的值。至此實現(xiàn)異步操作的控制。 你能學到什么 如何使用 Generator + Promise 實現(xiàn)異步編程 異步編程的原理解析 前言 結合 上一篇文章 ,我們來聊聊 Generator 基礎原理...
摘要:對于而言,異步編程我們可以采用回調函數(shù),事件監(jiān)聽,發(fā)布訂閱等方案,在之后,又新添了,,的方案。總結本文闡述了從回調函數(shù)到的演變歷史。參考文檔深入掌握異步編程系列理解的 對于JS而言,異步編程我們可以采用回調函數(shù),事件監(jiān)聽,發(fā)布訂閱等方案,在ES6之后,又新添了Promise,Genertor,Async/Await的方案。本文將闡述從回調函數(shù)到Async/Await的演變歷史,以及它們...
摘要:環(huán)境中產生異步操作的函數(shù)分為兩大類計時函數(shù)和函數(shù)。如果要在應用中定義復雜的異步操作,就要使用者兩類異步函數(shù)作為基本的構造快。在本例子中同步事件循環(huán)不包含內部的外部的異步事件循環(huán)內部的。其弊端是操作強耦合維護代價高。 JavaScript環(huán)境中產生異步操作的函數(shù)分為兩大類:計時函數(shù)和I/O函數(shù)。如果要在應用中定義復雜的異步操作,就要使用者兩類異步函數(shù)作為基本的構造快。本文沒有對某個知識點...
摘要:換句話說,當一個異步過程調用發(fā)出后,調用者不會立刻得到結果。參考文章珠峰架構課墻裂推薦細說異步函數(shù)發(fā)展歷程異步編程謝謝各位小伙伴愿意花費寶貴的時間閱讀本文,如果本文給了您一點幫助或者是啟發(fā),請不要吝嗇你的贊和,您的肯定是我前進的最大動力。知其然知其所以然,首先了解三個概念: 1.什么是同步? 所謂同步,就是在發(fā)出一個調用時,在沒有得到結果之前,該調用就不返回。但是一旦調用返回,就得到返回值了...
閱讀 1113·2021-11-19 09:40
閱讀 969·2021-11-12 10:36
閱讀 1259·2021-09-22 16:04
閱讀 3106·2021-09-09 11:39
閱讀 1266·2019-08-30 10:51
閱讀 1882·2019-08-30 10:48
閱讀 1221·2019-08-29 16:30
閱讀 464·2019-08-29 12:37