摘要:而在中是迭代器生成器,被創(chuàng)造性的拿來做異步流程控制了。當(dāng)執(zhí)行的時候,并不執(zhí)行函數(shù)體,而是返回一個迭代器。行代碼再看看文章開頭的行代碼首先生成一個迭代器,然后執(zhí)行一遍,得到的是一個對象,里面再執(zhí)行。
廣告招人:阿里巴巴招前端,在這里你可以享受大公司的福利和技術(shù)體系,也有小團隊的挑戰(zhàn)和成長空間。
聯(lián)系: qingguang.meiqg at alibaba-inc.com
首先請原諒我的標(biāo)題黨(●—●),tj 大神的 co 模塊源碼200多行,顯然不是我等屌絲能隨便幾行代碼就能重寫的。只是當(dāng)今大家都喜歡《7天學(xué)會xx語言》之類的速效仙丹,于是我也弄個類似的名字《7行代碼學(xué)會co模塊》來博眼球。
為了避免被拖出去彈小JJ,還是先放出所謂的 7 行代碼給大家壓壓驚:
function co(gen) { var it = gen(); var ret = it.next(); ret.value.then(function(res) { it.next(res); }); }萬惡的回調(diào)
對前端工程師來說,異步回調(diào)是再熟悉不過了,瀏覽器中的各種交互邏輯都是通過事件回調(diào)實現(xiàn)的,前端邏輯越來越復(fù)雜,導(dǎo)致回調(diào)函數(shù)越來越多,同時 nodejs 的流行也讓 javascript 在后端的復(fù)雜場景中得到應(yīng)用,在 nodejs 代碼中更是經(jīng)常看到層層嵌套。
以下是一個典型的異步場景:先通過異步請求獲取頁面數(shù)據(jù),然后根據(jù)頁面數(shù)據(jù)請求用戶信息,最后根據(jù)用戶信息請求用戶的產(chǎn)品列表。過多的回調(diào)函數(shù)嵌套,使得程序難以維護(hù),發(fā)展成萬惡的回調(diào)。
$.get("/api/data", function(data) { console.log(data); $.get("/api/user", function(user) { console.log(user); $.get("/api/products", function(products) { console.log(products) }); }); });異步流程控制
最原始異步流程的寫法,就是類似上面例子里的回調(diào)函數(shù)嵌套法,用過的人都知道,那叫一個酸爽。
后來出現(xiàn)了 Promise ,它極大提高了代碼的可維護(hù)性,消除了萬惡的回調(diào)嵌套問題,并且現(xiàn)在已經(jīng)成為 ES6 標(biāo)準(zhǔn)的一部分。
$.get("/api/data") .then(function(data) { console.log(data); return $.get("/api/user"); }) .then(function(user) { console.log(user); return $.get("/api/products"); }) .then(function(products) { console.log(products); });
之后在 nodejs 圈出現(xiàn)了 co 模塊,它基于 ES6 的 generator 和 yield ,讓我們能用同步的形式編寫異步代碼。
co(function *() { var data = yield $.get("/api/data"); console.log(data); var user = yield $.get("/api/user"); console.log(user); var products = yield $.get("/api/products"); console.log(products); });
以上的 Promise 和 generator 最初創(chuàng)造它的本意都不是為了解決異步流程控制。其中 Promise 是一種編程思想,用于“當(dāng)xx數(shù)據(jù)準(zhǔn)備完畢,then執(zhí)行xx動作”這樣的場景,不只是異步,同步代碼也可以用 Promise。而 generator 在 ES6 中是迭代器生成器,被 TJ 創(chuàng)造性的拿來做異步流程控制了。真正的異步解決方案請大家期待 ES7 的 async 吧!本文以下主要介紹 co 模塊。
co 模塊上文已經(jīng)簡單介紹了co 模塊是能讓我們以同步的形式編寫異步代碼的 nodejs 模塊,主要得益于 ES6 的 generator。nodejs >= 0.11 版本可以加 --harmony 參數(shù)來體驗 ES6 的 generator 特性,iojs 則已經(jīng)默認(rèn)開啟了 generator 的支持。
要了解 co ,就不得不先簡單了解下 ES6 的 generator 和 iterator。
IteratorIterator 迭代器是一個對象,知道如何從一個集合一次取出一項,而跟蹤它的當(dāng)前序列所在的位置,它提供了一個next()方法返回序列中的下一個項目。
var lang = { name: "JavaScript", birthYear: 1995 }; var it = Iterator(lang); var pair = it.next(); console.log(pair); // ["name", "JavaScript"] pair = it.next(); console.log(pair); // ["birthYear", 1995] pair = it.next(); // A StopIteration exception is thrown
乍一看好像沒什么奇特的,不就是一步步的取對象中的 key 和 value 嗎,for ... in也能做到,但是把它跟 generator 結(jié)合起來就大有用途了。
GeneratorGenerator 生成器允許你通過寫一個可以保存自己狀態(tài)的的簡單函數(shù)來定義一個迭代算法。
Generator 是一種可以停止并在之后重新進(jìn)入的函數(shù)。生成器的環(huán)境(綁定的變量)會在每次執(zhí)行后被保存,下次進(jìn)入時可繼續(xù)使用。generator 字面上是“生成器”的意思,在 ES6 里是迭代器生成器,用于生成一個迭代器對象。
function *gen() { yield "hello"; yield "world"; return true; }
以上代碼定義了一個簡單的 generator,看起來就像一個普通的函數(shù),區(qū)別是function關(guān)鍵字后面有個*號,函數(shù)體內(nèi)可以使用yield語句進(jìn)行流程控制。
var iter = gen(); var a = iter.next(); console.log(a); // {value:"hello", done:false} var b = iter.next(); console.log(b); // {value:"world", done:false} var c = iter.next(); console.log(c); // {value:true, done:true}
當(dāng)執(zhí)行gen()的時候,并不執(zhí)行 generator 函數(shù)體,而是返回一個迭代器。迭代器具有next()方法,每次調(diào)用 next() 方法,函數(shù)就執(zhí)行到yield語句的地方。next() 方法返回一個對象,其中value屬性表示 yield 關(guān)鍵詞后面表達(dá)式的值,done 屬性表示是否遍歷結(jié)束。generator 生成器通過next和yield的配合實現(xiàn)流程控制,上面的代碼執(zhí)行了三次 next() ,generator 函數(shù)體才執(zhí)行完畢。
co 模塊思路從上面的例子可以看出,generator 函數(shù)體可以停在 yield 語句處,直到下一次執(zhí)行 next()。co 模塊的思路就是利用 generator 的這個特性,將異步操作跟在 yield 后面,當(dāng)異步操作完成并返回結(jié)果后,再觸發(fā)下一次 next() 。當(dāng)然,跟在 yield 后面的異步操作需要遵循一定的規(guī)范 thunks 和 promises。
yieldables7行代碼The yieldable objects currently supported are:
promises
thunks (functions)
array (parallel execution)
objects (parallel execution)
generators (delegation)
generator functions (delegation)
再看看文章開頭的7行代碼:
function co(gen) { var it = gen(); var ret = it.next(); ret.value.then(function(res) { it.next(res); }); }
首先生成一個迭代器,然后執(zhí)行一遍 next(),得到的 value 是一個 Promise 對象,Promise.then() 里面再執(zhí)行 next()。當(dāng)然這只是一個原理性的演示,很多錯誤處理和循環(huán)調(diào)用 next() 的邏輯都沒有寫出來。
下面做個簡單對比:
傳統(tǒng)方式,sayhello是一個異步函數(shù),執(zhí)行helloworld會先輸出"world"再輸出"hello"。
function sayhello() { return Promise.resolve("hello").then(function(hello) { console.log(hello); }); } function helloworld() { sayhello(); console.log("world"); } helloworld();
輸出
> "world" > "hello"
co 的方式,會先輸出"hello"再輸出"world"。
function co(gen) { var it = gen(); var ret = it.next(); ret.value.then(function(res) { it.next(res); }); } function sayhello() { return Promise.resolve("hello").then(function(hello) { console.log(hello); }); } co(function *helloworld() { yield sayhello(); console.log("world"); });
輸出
> "hello" > "world"消除回調(diào)金字塔
假設(shè)sayhello/sayworld/saybye是三個異步函數(shù),用真正的 co 模塊就可以這么寫:
var co = require("co"); co(function *() { yield sayhello(); yield sayworld(); yield saybye(); });
輸出
> "hello" > "world" > "bye"參考
《es7-async》 https://github.com/jaydson/es7-async
《Generator 函數(shù)的含義與用法》 http://www.ruanyifeng.com/blog/2015/04/generator.html
《Iterator》 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/85668.html
摘要:所以僅用于簡化理解,快速入門,依然需要閱讀有深入研究的文章來加深對各種異步流程控制的方法的掌握。 原文地址:http://zodiacg.net/2015/08/javascript-async-control-flow/ 隨著ES6標(biāo)準(zhǔn)逐漸成熟,利用Promise和Generator解決回調(diào)地獄問題的話題一直很熱門。但是對解決流程控制/回調(diào)地獄問題的各種工具認(rèn)識仍然比較麻煩。最近兩天...
摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡介現(xiàn)在,越來越多的科技公司和開發(fā)者開始使用開發(fā)各種應(yīng)用。 說明 2017-12-14 我發(fā)了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當(dāng)不錯的,甚至連著名的hax賀老都很認(rèn)同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...
摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡介現(xiàn)在,越來越多的科技公司和開發(fā)者開始使用開發(fā)各種應(yīng)用。 說明 2017-12-14 我發(fā)了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當(dāng)不錯的,甚至連著名的hax賀老都很認(rèn)同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...
摘要:淺析筆者在此整理了常見的命令,的重要性無需多言,與其再百度海中搜索命令,不妨嘗試收藏筆者的此篇作品。旨在快速高效地處理無論規(guī)模大小的任何軟件工程。其最大特色就是分支及合并操作非常快速簡便。 淺析git 筆者在此整理了常見的git命令,git的重要性無需多言,與其再百度海中搜索git命令,不妨嘗試收藏筆者的此篇作品。希望對你的學(xué)習(xí)有所幫助。 版本控制系統(tǒng)之git Git: (一)簡介:G...
閱讀 1844·2023-04-25 14:49
閱讀 3123·2021-09-30 09:47
閱讀 3111·2021-09-06 15:00
閱讀 2231·2019-08-30 13:16
閱讀 1443·2019-08-30 10:48
閱讀 2674·2019-08-29 15:11
閱讀 1294·2019-08-26 14:06
閱讀 1670·2019-08-26 13:30