亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

ES6 Generator與異步的同步書寫

andycall / 3104人閱讀

摘要:返回值是一個(gè)對(duì)象,它的第一個(gè)屬性是后面表達(dá)式的值或者的值第二個(gè)屬性表示函數(shù)是否執(zhí)行完成。真正的業(yè)務(wù)邏輯確實(shí)是用同步的方式寫的。

開始前

我們從來(lái)沒有停止過對(duì)javascript語(yǔ)言異步調(diào)用方式的改造,我們一直都想用像java那樣同步的方式去寫異步,盡管Promise可以讓我們將異步回調(diào)添加到then方法中,但是這種調(diào)用方式仍然不那么優(yōu)雅,es6 中新增加了generator,我們可以通過他的特性來(lái)實(shí)現(xiàn)異步任務(wù)更加優(yōu)雅的書寫方式。

協(xié)程介紹

協(xié)程其實(shí)和線程,進(jìn)程是沒有關(guān)系的,它不是操作系統(tǒng)為我們提供的api接口,而是通過編程語(yǔ)言或者匯編語(yǔ)言對(duì)程序上下文、程序棧來(lái)操作實(shí)現(xiàn)的。一個(gè)線程里面可以包含多個(gè)協(xié)程,線程的調(diào)度是由操作體統(tǒng)來(lái)決定的,協(xié)程的調(diào)度是由用戶來(lái)決定的。操作系統(tǒng)對(duì)其一無(wú)所知,因?yàn)榭梢杂捎脩魜?lái)調(diào)度,所以用來(lái)執(zhí)行協(xié)作式的任務(wù)特別方便。(注意這里是方便,因?yàn)槟芡ㄟ^協(xié)程解決的問題,通過線程和進(jìn)程也可以解決,但是復(fù)雜)

Generator介紹

Generator 是協(xié)程在es6中的實(shí)現(xiàn)。它在es6中是一個(gè)函數(shù),這個(gè)函數(shù)可以分階段執(zhí)行,也就是說我們可以在這個(gè)函數(shù)中的某個(gè)位置選擇交出當(dāng)前線程的執(zhí)行權(quán)限,也可以在當(dāng)前函數(shù)外面的某個(gè)位置選擇將權(quán)限再交回這個(gè)函數(shù),讓它繼續(xù)執(zhí)行,這種調(diào)度完全由用戶決定。在es6中協(xié)程函數(shù)是這樣的

function* gen(p) {
    var a = yield p + 1;  //1
    var b = yield p + 2;  //2
    return b;  //3
}

var g = gen(1);
g.next();  //{value: 2, done: false}
g.next();  //{value: 3, done: false}
g.next();  //{value: undefined, done: true}

通過 var g = gen(1); 僅僅是創(chuàng)建了一個(gè)迭代器,函數(shù) gen 里面的內(nèi)容并沒有執(zhí)行函數(shù)體的執(zhí)行時(shí)由第一個(gè) g.next(); 開始的 并且將 yield 所在那那條語(yǔ)句執(zhí)行完后就會(huì)返回結(jié)果。而后面的語(yǔ)句并沒有執(zhí)行。返回值是一個(gè)對(duì)象,它的第一個(gè)屬性是 yield 后面表達(dá)式的值 (p+1或者p+2的值);第二個(gè)屬性表示Generator函數(shù)是否執(zhí)行完成。這里我們通過 yield 執(zhí)行權(quán)限交出去,通過 next 將權(quán)限返回。

function* gen(p) {
    var a = yield p + 1;  //1
    var b = yield a + 1;  //2 注意這里是用到了 a
    return b;
}
var g = gen(1);
g.next();  //{value: 2, done: false}
g.next();  //{value: NaN, done: false} 這里的值是 NaN
g.next();  //{value: undefined, done: true}

g.next();  //{value: 2, done: false}
g.next(2);  //{value: 3, done: false}
g.next(6);  //{value: 6, done: true}

注意這里 //1 處 //2 處 var a = yield p + 1;這條賦值語(yǔ)句中 a 的值并不是 p + 1的值。這條語(yǔ)句只是一種寫法,這里 a 的值是我們?cè)诘诙€(gè) next 中傳入的 2 這個(gè)很重要 b 的值也是我們?cè)诘谌齻€(gè) next 中傳入的 6

Generator 的重要特性

由上面的內(nèi)容我們總結(jié) 3 個(gè)關(guān)于 Generator 的重要特性

1 通過 yield 交出執(zhí)行權(quán)限,通過 next 返回執(zhí)行權(quán)限
2 調(diào)用 next 會(huì)得到一個(gè)返回值,這個(gè)值里面包含了 yield 后面的表達(dá)式的執(zhí)行結(jié)果
3 我們可以通過給 next 傳遞參數(shù),并且可以在 Generator 函數(shù)中通過上面所寫的特殊方式來(lái)引用

利用 Generator 的特性來(lái)實(shí)現(xiàn)異步代碼的同步書寫

我們來(lái)模擬一個(gè)異步函數(shù)

function post(url, callback) {
    setTimeout(function() {
        var data = { //模擬異步處理結(jié)果
            url:url,
            value:10
        };
        callback(data);
    }, 1000);
}

post("http://_ivenj",function(data){
    console.log(data.url);  // http://_ivenj
    console.log(data.value);  //10
});

對(duì)應(yīng)上面的這個(gè)異步函數(shù)我想通過 Generator 來(lái)這樣用

function* gen(url) {
    var data = yield post(url);  //1
    console.log(data.url);
    console.log(data.value);
}
var g = gen("http://_ivenj");
var resultG = g.next();
g.next(resultG.value);

是的,這樣寫漂亮多了,很像 java 的同步寫法。不同之處就是多了個(gè) yield* ,這個(gè)無(wú)傷大雅。當(dāng)然以上這樣用肯定是不行的。因?yàn)?post 畢竟是個(gè)異步方法。沒有返回值.如果不能實(shí)現(xiàn)這樣的寫法我這半天就是在扯淡,所以通過包裝是可以實(shí)現(xiàn)的。

通過以下兩點(diǎn)可以實(shí)現(xiàn)以上的書寫方式

(1)我有一篇文章 react 實(shí)踐之 redux applyMiddleware方法詳解 中介紹了柯里化(Currying)這篇文章雖然是寫react的但是柯里化是獨(dú)立的,這里就要利用柯里化的思想

(2)我們要在回調(diào)中調(diào)用 next 來(lái)繼續(xù)執(zhí)行,(這里有人會(huì)想不是不用回調(diào)了么,怎么還用,請(qǐng)繼續(xù)看。。。)

我們要對(duì) post 的調(diào)用形式進(jìn)行包裝

function kPost(url) {
    return function(callback) {
        post(url, callback);
    }
}

通過這個(gè)包裝,我們就能保證調(diào)用 kPost 就會(huì)同步的得到一個(gè)返回值

function* gen(url) {
    var data = yield kPost(url);  //1
    console.log(data.url);
    console.log(data.value);
}
//這里執(zhí)行方式會(huì)不同
var g = gen("http://_ivenj");
//啟動(dòng)任務(wù)
var resultG1 = g.next();
var value_resultG1 = resultG1.value; //resultG1.value 一定是一個(gè)函數(shù),因?yàn)槲覀儼b了
value_resultG1(function(data){
    g.next(data);  //通過在異步的回調(diào)中調(diào)用 next 并傳遞值來(lái)確保依賴異步結(jié)果的代碼能正確執(zhí)行
});

下面就是整體代碼,是上面的片段組合,請(qǐng)你粘貼到瀏覽器控制臺(tái),或者用node運(yùn)行,就會(huì)看到想要的結(jié)果

function post(url, callback) {
    setTimeout(function() {
        var data = { //模擬異步處理結(jié)果
            url:url,
            value:10
        };
        callback(data);
    }, 1000);
}
function kPost(url) {
    return function(callback) {
        post(url, callback);
    }
}
function* gen(url) {
    var data = yield kPost(url);  //1
    console.log(data.url);
    console.log(data.value);
}
//這里執(zhí)行方式會(huì)不同
var g = gen("http://_ivenj");
//啟動(dòng)任務(wù)
var resultG1 = g.next();
var value_resultG1 = resultG1.value; //resultG1.value 一定是一個(gè)函數(shù),因?yàn)槲覀儼b了
value_resultG1(function(data){
    g.next(data);
});

有人會(huì)說,怎么不就是將異步回調(diào)轉(zhuǎn)移出來(lái)了么,還要寫回調(diào)。這說明你還沒有真正體會(huì)個(gè)中之奧妙。我們會(huì)發(fā)現(xiàn) 我們寫的異步

value_resultG1(function(data){
    g.next(data);
});

僅僅是調(diào)用了 next 進(jìn)行了結(jié)果的傳遞,這里面有共同之處,不管是哪一種異步,我們都只傳遞值。大家的處理都是一樣的。真正的業(yè)務(wù)邏輯確實(shí)是用同步的方式寫的。那么,我們可以將共同的地方提取出來(lái),寫一個(gè)通用的函數(shù)去執(zhí)行這個(gè)傳值操作,這樣,我們完全就告別了異步,再也看不到了,好開心。co.js就是一個(gè)這種generator的執(zhí)行庫(kù)。使用它是我們只需要將我們的 gen 傳遞給它像這樣 co(gen) 是的就這樣。下面我們自己寫一個(gè) co

Generator執(zhí)行器

function co(taskDef) {
    //獲取迭代器  類似 java 中的外柄迭代子
    var task = taskDef();
    //開始任務(wù)
    var result = task.next();
    //調(diào)用next的遞歸函數(shù)
    function step() {
        if (!result.done) {  //如果generator沒有執(zhí)行完
            if (typeof result.value === "function") {
                result.value(function(err, data) {
                    if (err) {
                        result = task.throw(err);
                        return;
                    }
                    result = task.next(data);  //向后傳遞當(dāng)前異步處理結(jié)果
                    step();  //遞歸執(zhí)行
                });
            } else {
                result = task.next(result.value);  //如果執(zhí)行完了就傳遞值
                step();  //遞歸執(zhí)行
            }

        }
    }
    // 啟動(dòng)遞歸函數(shù)
    step();
}

通過 co 執(zhí)行的完整代碼

function post(url, callback) {
    setTimeout(function() {
        var data = { //模擬異步處理結(jié)果
            url:url,
            value:10
        };
        callback(data);
    }, 1000);
}
function kPost(url) {
    return function(callback) {
        post(url, callback);
    }
}
function gen(url) {
    return function* () {
        var data = yield kPost(url);  //1
        console.log(data.url);
        console.log(data.value);
    }
}
function co(taskDef) {
    var task = taskDef();
    //開始任務(wù)
    var result = task.next();
    // 調(diào)用next的遞歸函數(shù)
    function step() {
        if (!result.done) {  //如果generator沒有執(zhí)行完
            if (typeof result.value === "function") {
                result.value(function(err, data) {
                    if (err) {
                        result = task.throw(err);
                        return;
                    }
                    result = task.next(data);  //向后傳遞當(dāng)前異步處理結(jié)果
                    step();  //遞歸執(zhí)行
                });
            } else {
                result = task.next(result.value);  //如果執(zhí)行完了就傳遞值
                step();  //遞歸執(zhí)行
            }

        }
    }
    // 啟動(dòng)遞歸函數(shù)
    step();
}
    
co(gen("http://_ivenj")); //調(diào)用方式就是這么簡(jiǎn)單

以上代碼執(zhí)行 1s 后會(huì)拋出一個(gè)異常,并且正確打印{url: "http://_ivenj", value: 10},聰明的你一定知道為什么會(huì)拋出異常!!!

到這里已經(jīng)說明白了,并且也說完了,你會(huì)想是不是把異步包裝成Promise也可以呢,答案是肯定的,柯里化的思想只是一種實(shí)現(xiàn)方式,Promise 也是一種,你可以自己去琢磨,co.js 就是將兩種方式都實(shí)現(xiàn)了的一個(gè)執(zhí)行器。es7 中從語(yǔ)言層面對(duì) Generator 進(jìn)行了包裝,在es7 中我們可以使用 asyncawait更優(yōu)雅的實(shí)現(xiàn)類似java的順序書寫方式,asyncawaitGenerator的語(yǔ)法糖,在es7中內(nèi)置了執(zhí)行器。別人都說是終極方案。

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

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

相關(guān)文章

  • Generator同步代碼書寫異步情懷

    摘要:調(diào)用方法執(zhí)行到后暫停,內(nèi)部環(huán)境被保存,執(zhí)行返回一個(gè)對(duì)象,為的執(zhí)行結(jié)果,表示迭代器是否完成。當(dāng)?shù)魍瓿珊?,為,為的值,繼續(xù)執(zhí)行,將為執(zhí)行原理回到開頭的例子,給我們提供了直觀的寫法來(lái)處理異步回調(diào),它讓代碼邏輯非常清晰。 編者按:看完本文,你能對(duì)ES6的Generator有一個(gè)很好的理解,輕松地以同步的方式寫異步代碼,也能初步理解到TJ大神的co框架的原理。 前言:ES6在2015年6月正...

    hightopo 評(píng)論0 收藏0
  • 【W(wǎng)eb全棧課程三】ES6特性介紹(下)

    摘要:示例運(yùn)行函數(shù)彈出彈出函數(shù)接收參數(shù),返回值。其中,返回一個(gè)對(duì)象,是的返回值,代表函數(shù)是否執(zhí)行完成。 ES6特性介紹(下) ES6新的標(biāo)準(zhǔn),新的語(yǔ)法特征:1、變量/賦值2、函數(shù)3、數(shù)組/json4、字符串5、面向?qū)ο?、Promise7、generator8、ES7:async/await 《【W(wǎng)eb全棧課程二】ES6特性介紹(上)》見:https://segmentfault.com/a...

    wangshijun 評(píng)論0 收藏0
  • 深入前端-JavaScript異步編程

    摘要:缺點(diǎn)無(wú)法取消當(dāng)處于狀態(tài)時(shí),無(wú)法得知目前進(jìn)展到哪一個(gè)階段錯(cuò)誤不能被生成器什么是函數(shù)是提供的一種異步編程解決方案,語(yǔ)法行為與傳統(tǒng)函數(shù)完全不同函數(shù)有多種理解角度。 JavaScript的執(zhí)行機(jī)制在上篇文章中進(jìn)行了深入的探討,那么既然是一門單線程語(yǔ)言,如何進(jìn)行良好體驗(yàn)的異步編程呢 回調(diào)函數(shù)Callbacks 當(dāng)程序跑起來(lái)時(shí),一般情況下,應(yīng)用程序(application program)會(huì)時(shí)常通...

    2json 評(píng)論0 收藏0
  • 深入前端-JavaScript異步編程

    摘要:缺點(diǎn)無(wú)法取消當(dāng)處于狀態(tài)時(shí),無(wú)法得知目前進(jìn)展到哪一個(gè)階段錯(cuò)誤不能被生成器什么是函數(shù)是提供的一種異步編程解決方案,語(yǔ)法行為與傳統(tǒng)函數(shù)完全不同函數(shù)有多種理解角度。 JavaScript的執(zhí)行機(jī)制在上篇文章中進(jìn)行了深入的探討,那么既然是一門單線程語(yǔ)言,如何進(jìn)行良好體驗(yàn)的異步編程呢 回調(diào)函數(shù)Callbacks 當(dāng)程序跑起來(lái)時(shí),一般情況下,應(yīng)用程序(application program)會(huì)時(shí)常通...

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

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

0條評(píng)論

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