成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

ES6&ES7中的異步之Generator函數(shù)與異步編程

venmos / 2142人閱讀

摘要:傳統(tǒng)的異步方法回調(diào)函數(shù)事件監(jiān)聽(tīng)發(fā)布訂閱之前寫(xiě)過(guò)一篇關(guān)于的文章,里邊寫(xiě)過(guò)關(guān)于異步的一些概念。內(nèi)部函數(shù)就是的回調(diào)函數(shù),函數(shù)首先把函數(shù)的指針指向函數(shù)的下一步方法,如果沒(méi)有,就把函數(shù)傳給函數(shù)屬性,否則直接退出。

Generator函數(shù)與異步編程

因?yàn)閖s是單線程語(yǔ)言,所以需要異步編程的存在,要不效率太低會(huì)卡死。

傳統(tǒng)的異步方法

回調(diào)函數(shù)

事件監(jiān)聽(tīng)

發(fā)布/訂閱

Promise

之前寫(xiě)過(guò)一篇關(guān)于Promise的文章,里邊寫(xiě)過(guò)關(guān)于異步的一些概念。這篇文章將會(huì)說(shuō)一下Generator函數(shù)的異步應(yīng)用。

Generator函數(shù) 協(xié)程

多個(gè)線程互相合作完成任務(wù),在傳統(tǒng)的編程語(yǔ)言中(比如java),當(dāng)A線程在執(zhí)行,執(zhí)行一段時(shí)間之后暫停,由B線程繼續(xù)執(zhí)行,B線程執(zhí)行結(jié)束之后A線程再執(zhí)行,這個(gè)時(shí)候,A線程就被稱為協(xié)程,而這個(gè)協(xié)程A就是異步任務(wù)。

function* foo(){
    ... //其他代碼
    var f = readFile();
    ... //其他代碼
}

上邊這個(gè)函數(shù),foo函數(shù)就是一個(gè)協(xié)程,通過(guò)yield命令實(shí)現(xiàn)協(xié)程的暫停,等到讀取文件的函數(shù)執(zhí)行完畢之后,再繼續(xù)執(zhí)行foo其他的操作。

協(xié)程的Generator函數(shù)實(shí)現(xiàn)

Generator函數(shù)是協(xié)程在ES6的實(shí)現(xiàn),最大的特點(diǎn)是交出函數(shù)的執(zhí)行權(quán)(暫停函數(shù)執(zhí)行)

整個(gè)Generator函數(shù)就是一個(gè)封裝好了的異步任務(wù),而yield是函數(shù)暫停執(zhí)行的標(biāo)志。

function* foo(){
    let x = 1;
    let y = yield x + 2;
    return y
}

var f = foo()
f.next();   // {value:3,done:false}
f.next();   // {value:undefined,done:true}

next方法的作用是分批端執(zhí)行Generator函數(shù)。
異步函數(shù)的封裝
let fetch = require("node-fetch")

function* asynsFun(){
    let url = "....";
    var f = yield fetch(url);
    console.log(f)
}

當(dāng)執(zhí)行完fetch之后把取回的數(shù)據(jù)賦值給f,然后再把f打印出來(lái),這個(gè)看起來(lái)很像同步的寫(xiě)法,但是實(shí)現(xiàn)起來(lái)卻是異步的。

是不是很簡(jiǎn)單,如果用回掉函數(shù)或者Promise的寫(xiě)法會(huì)很復(fù)雜的。

let a = asyncFun()
a.next()

a.value.then(function(data){
  return data.json();
}).then(function(data){
  g.next(data);
});

這樣的寫(xiě)法表示起來(lái)很簡(jiǎn)潔,但是流程管理比較復(fù)雜。

Thunk函數(shù)

thunk函數(shù)是自動(dòng)執(zhí)行Generator函數(shù)的一種方法。

Thunk函數(shù)的核心理解就是傳名調(diào)用。

function f(x){
    return x * 2
}

f(x + 6)

//等同于

var thunk = function(x) {
    return x + 5
}

function f() {
    return thunk() * 2 
}

理論上,x+6被thunk函數(shù)替代了,所有用到原來(lái)參數(shù)的地方,直接用thunk求值就行。

這就是Thunk函數(shù)的策略,是傳名求值的一種實(shí)現(xiàn)策略,用來(lái)替換某個(gè)表達(dá)式。

js中的Thunk函數(shù)

在js中,函數(shù)的參數(shù)并不是傳名的而是傳值的,所以,thunk函數(shù)不是用來(lái)替換表達(dá)式的,而是用來(lái)替換多參數(shù)函數(shù)的。將其中一個(gè)參數(shù)替換成只接收一個(gè)回掉函數(shù)的單參數(shù)參數(shù)。

聽(tīng)起來(lái)很拗口,看代碼。

// 正常的寫(xiě)法
fs.readFile(filename,callback);

// thunk函數(shù)的單參數(shù)版本
var thunk = function(filename) {
    return function(callback) {
        return fs.readFile(filename,callback);
    }
}

var readThunk = thunk(filename)
readThunk(callback)

理論上,只要函數(shù)的一個(gè)參數(shù)是回調(diào)函數(shù),就可以改寫(xiě)成Thunk函數(shù)。

Thunkify模塊

一個(gè)轉(zhuǎn)換器,把函數(shù)轉(zhuǎn)成Thunk函數(shù)

安裝
npm install thunkify

使用方法:
var thunkify = require("thunkify");
var fs = require("fs");

var read = thunkify(rs.readFile);
read("package-json")(function(err,str)
    // ...
)

thunkify接受一個(gè)回調(diào)方法、

Generator函數(shù)的流程管理

之前說(shuō)過(guò),Generator函數(shù)的流程管理比較復(fù)雜,那么Thunk函數(shù)有什么用呢,正確答案是,他可以幫助Generator函數(shù)實(shí)現(xiàn)自動(dòng)的流程管理。

function* gen(){
    // ...
}
var g = gen();
var res = g.next();

while(!res.done){
    console.log(res.value)
    res.next();
}

理論上,上面的代碼可以實(shí)現(xiàn)自動(dòng)執(zhí)行,但是,不能適合異步。用Thunk可以解決這個(gè)問(wèn)題。

var thunkify = require("thunkify");
var fs = require("fs");
var readFileThunk = thunkify(fs.readFile)

var gen = function* (){
    var r1 = readFileThunk("filename1")
    console.log(r1);
    var r2 = readFileThunk("filename2")
    console.log(r2);
    
}
Thunk函數(shù)的自動(dòng)流程管理

Thunk函數(shù)的真正意義在于可以自動(dòng)執(zhí)行Generator函數(shù),看下邊的例子。

function* g(){
    // ...
}

function run(fn){    //Thunk函數(shù)接收一個(gè)Generator函數(shù)
    var gen = fn();
    
    function next(err,data){
        var result = gen.next(data);
        if(result.done) return;
        return result.value(next)
    }
    
    next();
}

run(g)

解析一下這個(gè)代碼:
run方法其實(shí)就是一個(gè)Generator函數(shù)自動(dòng)執(zhí)行器。內(nèi)部函數(shù)next就是Thunk的回調(diào)函數(shù),next函數(shù)首先把Generator函數(shù)的指針指向Generator函數(shù)的下一步方法(gen.next()),如果沒(méi)有,就把next函數(shù)傳給Thunk函數(shù)(result.value屬性),否則直接退出。

有了這個(gè)執(zhí)行器,執(zhí)行Generator函數(shù)就方便多了,不管內(nèi)部多少操作,直接把Generator函數(shù)傳給run函數(shù)即可,當(dāng)然前提是每一個(gè)異步操作都是一個(gè)Thunk函數(shù),也就是yield后面的必須是Thunk函數(shù)。

function* g(){
    var f1 = yield fs.readFileThunk("filename1")
    var f2 = yield fs.readFileThunk("filename2")
    ...

}

run(g)

Thunk 函數(shù)并不是 Generator 函數(shù)自動(dòng)執(zhí)行的唯一方案。因?yàn)樽詣?dòng)執(zhí)行的關(guān)鍵是,必須有一種機(jī)制,自動(dòng)控制 Generator 函數(shù)的流程,接收和交還程序的執(zhí)行權(quán)。回調(diào)函數(shù)可以做到這一點(diǎn),Promise 對(duì)象也可以做到這一點(diǎn)。

這篇文章寫(xiě)得比較難懂,其實(shí)主要是為了下一篇文章做鋪墊。

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

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

相關(guān)文章

  • ES6&ES7中的異步async函數(shù)

    摘要:更好的語(yǔ)義和分別表示異步和等待,比起和更容易理解。前邊聲明關(guān)鍵字,表示內(nèi)部有內(nèi)部操作,調(diào)用函數(shù)會(huì)返回一個(gè)對(duì)象。等價(jià)于其中函數(shù)就是自動(dòng)執(zhí)行器。 async函數(shù) 定義 async函數(shù)其實(shí)就是之前說(shuō)過(guò)的Generator的語(yǔ)法糖,用于實(shí)現(xiàn)異步操作。它是ES2017的新標(biāo)準(zhǔn)。 讀取兩個(gè)文件: const fs = require(fs) const readFile = function(f...

    dongxiawu 評(píng)論0 收藏0
  • ES6&ES7中的異步Generator的語(yǔ)法

    摘要:第二次同理,遇到了第二個(gè)函數(shù)會(huì)停下來(lái),輸出的遍歷器對(duì)象值為,的值依然是。比如返回的遍歷器對(duì)象,都會(huì)有一個(gè)方法,這個(gè)方法掛在原型上。這三個(gè)函數(shù)共同的作用是讓函數(shù)恢復(fù)執(zhí)行。 Generator的語(yǔ)法 generator的英文意思是生成器 簡(jiǎn)介 關(guān)于Generator函數(shù),我們可以理解成是一個(gè)狀態(tài)機(jī),里面封裝了多種不同的狀態(tài)。 function* gener(){ yield hel...

    djfml 評(píng)論0 收藏0
  • ES6-7

    摘要:的翻譯文檔由的維護(hù)很多人說(shuō),阮老師已經(jīng)有一本關(guān)于的書(shū)了入門(mén),覺(jué)得看看這本書(shū)就足夠了。前端的異步解決方案之和異步編程模式在前端開(kāi)發(fā)過(guò)程中,顯得越來(lái)越重要。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(shū)(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書(shū)的目的是以目前還在制定中的ECMASc...

    mudiyouyou 評(píng)論0 收藏0
  • ES6 Generator異步的同步書(shū)寫(xiě)

    摘要:返回值是一個(gè)對(duì)象,它的第一個(gè)屬性是后面表達(dá)式的值或者的值第二個(gè)屬性表示函數(shù)是否執(zhí)行完成。真正的業(yè)務(wù)邏輯確實(shí)是用同步的方式寫(xiě)的。 開(kāi)始前 我們從來(lái)沒(méi)有停止過(guò)對(duì)javascript語(yǔ)言異步調(diào)用方式的改造,我們一直都想用像java那樣同步的方式去寫(xiě)異步,盡管Promise可以讓我們將異步回調(diào)添加到then方法中,但是這種調(diào)用方式仍然不那么優(yōu)雅,es6 中新增加了generator,我們可以通...

    andycall 評(píng)論0 收藏0
  • Promise & Generator——幸福地用同步方法寫(xiě)異步JavaScript

    摘要:在這里看尤雨溪大神的這篇小短文,非常精簡(jiǎn)扼要地介紹了當(dāng)前常用的。根據(jù)尤雨溪大神的說(shuō)法,的也只是的語(yǔ)法糖而已。對(duì)象有三種狀態(tài),,。對(duì)象通過(guò)和方法來(lái)規(guī)定異步結(jié)束之后的操作正確處理函數(shù)錯(cuò)誤處理函數(shù)。方便進(jìn)行后續(xù)的成功處理或者錯(cuò)誤處理。 最近在寫(xiě)一個(gè)自己的網(wǎng)站的時(shí)候(可以觀摩一下~Colors),在無(wú)意識(shí)中用callback寫(xiě)了一段嵌套了5重回調(diào)函數(shù)的可怕的代碼?;剡^(guò)神來(lái)的時(shí)候被自己嚇了一跳,...

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

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

0條評(píng)論

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