国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

秒殺 tj/co 的 hprose 協(xié)程庫(kù)

EddieChan / 538人閱讀

摘要:而這對(duì)于回調(diào)函數(shù)只有一個(gè)返回值參數(shù)的函數(shù),或者回調(diào)函數(shù)的第一個(gè)參數(shù)不表示錯(cuò)誤的函數(shù)來(lái)說(shuō),庫(kù)就無(wú)法使用了。當(dāng)對(duì)函數(shù)進(jìn)行時(shí),如果回調(diào)函數(shù)第一個(gè)參數(shù)是類型的對(duì)象才會(huì)被當(dāng)做錯(cuò)誤處理。因此,第二個(gè)回合,仍然是完勝和。

ES6 中引入了 Generator,Generator 通過封裝之后,可以作為協(xié)程來(lái)進(jìn)行使用。

其中對(duì) Generator 封裝最為著名的當(dāng)屬 tj/co,但是 tj/co 跟 ES2016 的 async/await 相比的話,還存在一些比較嚴(yán)重的缺陷。

hprose 中也引入了對(duì) Generator 封裝的協(xié)程支持,但是比 tj/co 更加完善,下面我們就來(lái)詳細(xì)介紹一下它們之間的差別。

tj/co 有以下幾個(gè)方面的問題:

首先,tj/co 庫(kù)中的 yield 只支持 thunk 函數(shù),生成器函數(shù),promise 對(duì)象,以及數(shù)組和對(duì)象,但是不支持普通的基本類型的數(shù)據(jù),比如 null, 數(shù)字,字符串等都不支持。這對(duì)于 yield 一個(gè)類型不確定的變量來(lái)說(shuō),是很不方便的。而且這跟 await 也是不兼容的。

其次,在 yield 數(shù)組和對(duì)象時(shí),tj/co 庫(kù)會(huì)自動(dòng)對(duì)數(shù)組中的元素和對(duì)象中的字段遞歸的遍歷,將其中的所有的 Promise 元素和字段替換為實(shí)際值,這對(duì)于簡(jiǎn)單的數(shù)據(jù)來(lái)說(shuō),會(huì)方便一些。但是對(duì)于帶有循環(huán)引用的數(shù)組和對(duì)象來(lái)說(shuō),會(huì)導(dǎo)致無(wú)法獲取到結(jié)果,這是一個(gè)致命的問題。即使對(duì)于不帶有循環(huán)引用結(jié)構(gòu)的數(shù)組和對(duì)象來(lái)說(shuō),如果該數(shù)組和對(duì)象比較復(fù)雜,這也會(huì)消耗大量的時(shí)間。而且這跟 await 也是不兼容的。

再次,對(duì)于 thunk 函數(shù),tj/co 庫(kù)會(huì)認(rèn)為回調(diào)函數(shù)第一個(gè)參數(shù)必須是表示錯(cuò)誤,從第二個(gè)參數(shù)開始才表示返回值。而這對(duì)于回調(diào)函數(shù)只有一個(gè)返回值參數(shù)的函數(shù),或者回調(diào)函數(shù)的第一個(gè)參數(shù)不表示錯(cuò)誤的函數(shù)來(lái)說(shuō),tj/co 庫(kù)就無(wú)法使用了。

hprose.co 對(duì) yield 的支持則跟 await 完全兼容,支持對(duì)所有類型的數(shù)據(jù)進(jìn)行 yield

當(dāng) hprose.co 對(duì) chunk 函數(shù)進(jìn)行 yield 時(shí),如果回調(diào)函數(shù)第一個(gè)參數(shù)是 Error 類型的對(duì)象才會(huì)被當(dāng)做錯(cuò)誤處理。如果回調(diào)函數(shù)只有一個(gè)參數(shù)且不是 Error 類型的對(duì)象,則作為返回值對(duì)待。如果回調(diào)函數(shù)有兩個(gè)以上的參數(shù),如果第一個(gè)參數(shù)為 nullundefined,則第一個(gè)參數(shù)被當(dāng)做無(wú)錯(cuò)誤被忽略,否則,全部回調(diào)參數(shù)都被當(dāng)做返回值對(duì)待。如果被當(dāng)做返回值的回調(diào)參數(shù)有多個(gè),則這多個(gè)參數(shù)被當(dāng)做數(shù)組結(jié)果對(duì)待,如果只有一個(gè),則該參數(shù)被直接當(dāng)做返回值對(duì)待。

下面我們來(lái)舉例說(shuō)明一下:

yield 基本類型

首先我們來(lái)看一下 tj/co 庫(kù)的例子:

var co = require("co");

co(function*() {
    try {
        console.log(yield Promise.resolve("promise"));
        console.log(yield function *() { return "generator" });
        console.log(yield new Date());
        console.log(yield 123);
        console.log(yield 3.14);
        console.log(yield "hello");
        console.log(yield true);
    }
    catch (e) {
        console.error(e);
    }
});

該程序運(yùn)行結(jié)果為:

promise
generator
TypeError: You may only yield a function, promise, generator, array, or object, but the following object was passed: "Sat Nov 19 2016 14:51:09 GMT+0800 (CST)"
    at next (/usr/local/lib/node_modules/co/index.js:101:25)
    at onFulfilled (/usr/local/lib/node_modules/co/index.js:69:7)
    at process._tickCallback (internal/process/next_tick.js:103:7)
    at Module.runMain (module.js:577:11)
    at run (bootstrap_node.js:352:7)
    at startup (bootstrap_node.js:144:9)
    at bootstrap_node.js:467:3

其實(shí)除了前兩個(gè),后面的幾個(gè)基本類型的數(shù)據(jù)都不能被 yield。如果我們把上面代碼的第一句改為:

var co = require("hprose").co;

后面的代碼都不需要修改,我們來(lái)看看運(yùn)行結(jié)果:

promise
generator
2016-11-19T06:54:30.081Z
123
3.14
hello
true

也就是說(shuō),hprose.co 支持對(duì)所有類型進(jìn)行 yield 操作。下面我們?cè)賮?lái)看看 async/await 是什么效果:

(async function() {
    try {
        console.log(await Promise.resolve("promise"));
        console.log(await function *() { return "generator" });
        console.log(await new Date());
        console.log(await 123);
        console.log(await 3.14);
        console.log(await "hello");
        console.log(await true);
    }
    catch (e) {
        console.error(e);
    }
})();

上面的代碼基本上就是把 co(function*...) 替換成了 async function...,把 yield 替換成了 await。

我們來(lái)運(yùn)行上面的程序,注意,對(duì)于當(dāng)前版本的 node 運(yùn)行時(shí)需要加上 --harmony_async_await 參數(shù),運(yùn)行結(jié)果如下:

promise
[Function]
2016-11-19T08:16:25.316Z
123
3.14
hello
true

我們可以看出,awaithprose.co 除了對(duì)生成器的處理不同以外,其它的都相同。對(duì)于生成器函數(shù),await 是按原樣返回的,而 hprose.co 則是按照 tj/co 的方式處理。也就是說(shuō) hprose.co 綜合了 awaittj/co 的全部?jī)?yōu)點(diǎn)。使用 hprose.co 比使用 awaittj/co 都方便。

yield 數(shù)組或?qū)ο?/b>

我們來(lái)看第二個(gè)讓 tj/co 崩潰的例子:

var co = require("co");

co(function*() {
    try {
        var a = [];
        for (i = 0; i < 1000000; i++) {
            a[i] = i;
        }
        var start = Date.now();;
        yield a;
        var end = Date.now();;
        console.log(end - start);
    }
    catch (e) {
        console.error(e);
    }
});

co(function*() {
    try {
        var a = [];
        a[0] = a;
        console.log(yield a);
    }
    catch (e) {
        console.error(e);
    }
});

co(function*() {
    try {
        var o = {};
        o.self = o;
        console.log(yield o);
    }
    catch (e) {
        console.error(e);
    }
});

運(yùn)行該程序,我們會(huì)看到程序會(huì)卡一會(huì)兒,然后出現(xiàn)下面的結(jié)果:

2530
(node:70754) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): RangeError: Maximum call stack size exceeded
(node:70754) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:70754) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): RangeError: Maximum call stack size exceeded

上面的 2530 是第一個(gè) co 程序段輸出的結(jié)果,也就是說(shuō)這個(gè) yield 要等待 2.5 秒才能返回結(jié)果。而后面兩個(gè) co 程序段則直接調(diào)用棧溢出了。如果在實(shí)際應(yīng)用中,出現(xiàn)了這樣的數(shù)據(jù),使用 tj/co 你的程序就會(huì)變得很慢,或者直接崩潰了。

下面看看 hprose.co 的效果,同樣只替換第一句話為:

var co = require("hprose").co;

后面的代碼都不需要修改,我們來(lái)看看運(yùn)行結(jié)果:

7
[ [Circular] ]
{ self: [Circular] }

第一個(gè) co 程序段用時(shí)很短,只需要 7 ms。注意,這還是包含了后面兩個(gè)程序段的時(shí)間,因?yàn)檫@三個(gè)協(xié)程是并發(fā)的,如果去掉后面兩個(gè)程序段,你看的輸出可能是 1 ms 或者 0 ms。而后面兩個(gè)程序段也完美的返回了帶有循環(huán)引用的數(shù)據(jù)。這才是我們期望的結(jié)果。

我們?cè)賮?lái)看看 async/await 下是什么效果,程序代碼如下:

(async function() {
    try {
        var a = [];
        for (i = 0; i < 1000000; i++) {
            a[i] = i;
        }
        var start = Date.now();
        await a;
        var end = Date.now();
        console.log(end - start);
    }
    catch (e) {
        console.error(e);
    }
})();

(async function() {
    try {
        var a = [];
        a[0] = a;
        console.log(await a);
    }
    catch (e) {
        console.error(e);
    }
})();

(async function() {
    try {
        var o = {};
        o.self = o;
        console.log(await o);
    }
    catch (e) {
        console.error(e);
    }
})();

運(yùn)行結(jié)果如下:

14
[ [Circular] ]
{ self: [Circular] }

我們發(fā)現(xiàn) async/await 的輸出結(jié)果跟 hprose.co 是一致的,但是在性能上,hprose.co 則比 async/await 還要快 1 倍。因此,第二個(gè)回合,hprose.co 仍然是完勝 tj/coasync/await

yield thunk 函數(shù)

我們?cè)賮?lái)看看 tj/cotj/thunkify 是多么的讓人抓狂,以及 hprose.cohprose.thunkify 是如何優(yōu)雅的解決 tj/cotj/thunkify 帶來(lái)的這些讓人抓狂的問題的。

首先我們來(lái)看第一個(gè)問題:

tj/thunkify 返回的 thunk 函數(shù)的執(zhí)行結(jié)果是一次性的,不能像 promise 結(jié)果那樣被使用多次,我們來(lái)看看下面這個(gè)例子:

var co = require("co");
var thunkify = require("thunkify");

var sum = thunkify(function(a, b, callback) {
    callback(null, a + b);
});

co(function*() {
    var result = sum(1, 2);
    console.log(yield result);
    console.log(yield sum(2, 3));
    console.log(yield result);
});

這個(gè)例子很簡(jiǎn)單,輸出結(jié)果你猜是啥?

3
5
3

是上面的結(jié)果嗎?恭喜你,答錯(cuò)了!不過,這不是你的錯(cuò),而是 tj/thunkify 的錯(cuò),它的結(jié)果是:

3
5

什么?最后的 console.log(yield result) 輸出結(jié)果哪兒去了?不好意思,tj/thunkify 解釋說(shuō)是為了防止 callback 被重復(fù)執(zhí)行,所以就只能這么玩了。可是真的是這樣嗎?

我們來(lái)看看使用 hprose.cohprose.thunkify 的執(zhí)行結(jié)果吧,把開頭兩行換成下面三行:

var hprose = require("hprose");
var co = hprose.co;
var thunkify = hprose.thunkify;

其它代碼都不用改,運(yùn)行它,你會(huì)發(fā)現(xiàn)預(yù)期的結(jié)果出來(lái)了,就是:

3
5
3

可能你還不服氣,你會(huì)說(shuō),tj/thunkify 這樣做是為了防止類似被 thunkify 的函數(shù)中,回調(diào)被多次調(diào)用時(shí),yield 的結(jié)果不正確,比如:

var sum = thunkify(function(a, b, callback) {
    callback(null, a + b);
    callback(null, a + b + a);
});

co(function*() {
    var result = sum(1, 2);
    console.log(yield result);
    console.log(yield sum(2, 3));
    console.log(yield result);
});

如果 tj/thunkify 不這樣做,結(jié)果可能就會(huì)變成:

3
4
5

可是真的是這樣嗎?你會(huì)發(fā)現(xiàn),即使改成上面的樣子,hprose.thunkify 配合 hprose.co 返回的結(jié)果仍然是:

3
5
3

跟預(yù)期的一樣,回調(diào)函數(shù)并沒有重復(fù)執(zhí)行,錯(cuò)誤的結(jié)果并沒有出現(xiàn)。而且當(dāng)需要重復(fù) yield 結(jié)果函數(shù)時(shí),還能夠正確得到結(jié)果。

最后我們?cè)賮?lái)看一下,tj/thunkify 這樣做真的解決了問題了嗎?我們把代碼改成下面這樣:

var sum = thunkify(function(a, b, callback) {
    console.log("call sum(" + Array.prototype.join.call(arguments) + ")");
    callback(null, a + b);
    callback(null, a + b + a);
});

co(function*() {
    var result = sum(1, 2);
    console.log(yield result);
    console.log(yield sum(2, 3));
    console.log(yield result);
});

然后替換不同的 cothunkify,然后執(zhí)行,我們會(huì)發(fā)現(xiàn),tj 版本的輸出如下:

call sum(1,2,function (){
        if (called) return;
        called = true;
        done.apply(null, arguments);
      })
3
call sum(2,3,function (){
        if (called) return;
        called = true;
        done.apply(null, arguments);
      })
5
call sum(1,2,function (){
        if (called) return;
        called = true;
        done.apply(null, arguments);
      },function (){
        if (called) return;
        called = true;
        done.apply(null, arguments);
      })

hprose 版本的輸出結(jié)果如下:

call sum(1,2,function () {
                thisArg = this;
                results.resolve(arguments);
            })
3
call sum(2,3,function () {
                thisArg = this;
                results.resolve(arguments);
            })
5
3

從這里,我們可以看出,tj 版本的程序在執(zhí)行第二次 yield result 時(shí),簡(jiǎn)直錯(cuò)的離譜,它不但沒有讓我們得到預(yù)期的結(jié)果,反而還重復(fù)執(zhí)行了 thunkify 后的函數(shù),而且?guī)氲膮?shù)也完全不對(duì)了,所以,這是一個(gè)完全錯(cuò)誤的實(shí)現(xiàn)。

而從 hprose 版本的輸出來(lái)看,hprose 不但完美的避免了回調(diào)被重復(fù)執(zhí)行,而且保證了被 thunkify 后的函數(shù)執(zhí)行的結(jié)果被多次 yield 時(shí),也不會(huì)被重復(fù)執(zhí)行,而且還能夠得到預(yù)期的結(jié)果,可以實(shí)現(xiàn)跟返回 promise 對(duì)象一樣的效果。

tj 因?yàn)闆]有解決他所實(shí)現(xiàn)的 thunkify 函數(shù)帶來(lái)的這些問題,所以在后期推薦大家放棄 thunkify,轉(zhuǎn)而投奔到返回 promise 對(duì)象的懷抱中,而實(shí)際上,這個(gè)問題并非是不能解決的。

hprose 在對(duì) thunkify 函數(shù)的處理上,再次完勝 tj。而這個(gè)回合中,async/await 就不用提了,因?yàn)?async/await 完全不支持對(duì) thunk 函數(shù)進(jìn)行 await。

這還不是 hprose.cohprose.thunkify 的全部呢,再繼續(xù)看下面這個(gè)例子:

var sum = thunkify(function(a, b, callback) {
    callback(a + b);
});

co(function*() {
    var result = sum(1, 2);
    console.log(yield result);
    console.log(yield sum(2, 3));
    console.log(yield result);
});

這里開頭對(duì) hprosetj 版本的不同 cothunkify 實(shí)現(xiàn)的引用就省略了,請(qǐng)大家自行腦補(bǔ)。

上面這段程序,如果使用 tj 版本的 cothunkify 實(shí)現(xiàn),運(yùn)行結(jié)果是這樣的:

(node:75927) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): 3
(node:75927) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

而如果使用 hprose 版本的 cothunkify 實(shí)現(xiàn),運(yùn)行結(jié)果是這樣的:

3
5
3

hprose 版本的運(yùn)行結(jié)果再次符合預(yù)期,而 tj 版本的運(yùn)行結(jié)果再次讓人失望之極。

進(jìn)過上面三個(gè)回合的較量,我們發(fā)現(xiàn) hprose 的協(xié)程完勝 tjasync/await,而且 tj 的實(shí)現(xiàn)是慘敗,async/await 雖然比 tj 稍微好那么一點(diǎn),但是跟 hprose 所實(shí)現(xiàn)協(xié)程比起來(lái),也是望塵莫及。

所以,用 tj/coasync/await 感覺很不爽的同學(xué),可以試試 hprose.co 了,絕對(duì)讓你爽歪歪。

hprose 有 4 個(gè) JavaScript 版本,它們都支持上面的協(xié)程庫(kù),它們的地址分別是:

hprose for Node.js(oschina鏡像)

hprose for HTML5(oschina鏡像)

hprose for JavaScript(oschina鏡像)

hprose for 微信小程序(oschina鏡像)

另外,如果你不需要使用 hprose 序列化和遠(yuǎn)程調(diào)用的話,下面還有一個(gè)專門的從 hprose 中精簡(jiǎn)出來(lái)的 Promise A+ 實(shí)現(xiàn)和協(xié)程庫(kù):Future.js(oschina鏡像)

當(dāng)然該協(xié)程庫(kù)的功能不止于此,更多介紹請(qǐng)參見:

Promise 異步編程

協(xié)程

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/80996.html

相關(guān)文章

  • 在 PHP 中使用 Promise + co/yield 協(xié)程

    摘要:只要在調(diào)用異步函數(shù)時(shí)設(shè)置一個(gè)或多個(gè)回調(diào)函數(shù),函數(shù)就會(huì)在完成時(shí)自動(dòng)調(diào)用回調(diào)函數(shù)。要解決的問題是,如何將回調(diào)方法的參數(shù)從回調(diào)方法中傳遞出來(lái),讓它可以像同步函數(shù)的返回結(jié)果一樣,在回調(diào)函數(shù)以外的控制范圍內(nèi),可以傳遞和復(fù)用。 摘要: 我們知道 JavaScript 自從有了 Generator 之后,就有了各種基于 Generator 封裝的協(xié)程。其中 hprose 中封裝的 Promise 和...

    appetizerio 評(píng)論0 收藏0
  • Python:Tornado 第一章:異步及協(xié)程基礎(chǔ):第三節(jié):協(xié)程

    摘要:上一篇文章第一章異步及協(xié)程基礎(chǔ)第二節(jié)關(guān)鍵字下一篇文章第二章實(shí)戰(zhàn)演練開發(fā)網(wǎng)站第一節(jié)網(wǎng)站結(jié)構(gòu)使用協(xié)程可以開發(fā)出類似同步代碼的異步行為。協(xié)程函數(shù)可以通過以下三張方式調(diào)用在本身是協(xié)程的函數(shù)內(nèi)通過關(guān)鍵字調(diào)用。 上一篇文章:Python:Tornado 第一章:異步及協(xié)程基礎(chǔ):第二節(jié):Python關(guān)鍵字yield下一篇文章:Python:Tornado 第二章:實(shí)戰(zhàn)演練:開發(fā)Tornado網(wǎng)站:第...

    charles_paul 評(píng)論0 收藏0
  • imi v1.0 正式版,專注單體應(yīng)用 PHP 協(xié)程應(yīng)用開發(fā)框架

    摘要:年開發(fā)并發(fā)布框架現(xiàn)已停止維護(hù)。經(jīng)過一年實(shí)戰(zhàn),年月日,一周年之際正式發(fā)布版本。宇潤(rùn)部分開源項(xiàng)目我已通過碼云平臺(tái),向項(xiàng)目力所能及地捐款,聊表心意。所以,目前主打的還是單體應(yīng)用開發(fā)。協(xié)議的開發(fā),也是帶來(lái)的一大優(yōu)勢(shì)。 imi 介紹 showImg(https://segmentfault.com/img/bVbuab9?w=291&h=187); imi 是基于 PHP 協(xié)程應(yīng)用開發(fā)框架,它支...

    genefy 評(píng)論0 收藏0
  • ECMAScript6(16):異步編程

    摘要:異步編程程序執(zhí)行分為同步和異步,如果程序每執(zhí)行一步都需要等待上一步完成才能開始,此所謂同步。因此異步編程十分重要。 異步編程 程序執(zhí)行分為同步和異步,如果程序每執(zhí)行一步都需要等待上一步完成才能開始,此所謂同步。如果程序在執(zhí)行一段代碼的同時(shí)可以去執(zhí)行另一段代碼,等到這段代碼執(zhí)行完畢再吧結(jié)果交給另一段代碼,此所謂異步。比如我們需要請(qǐng)求一個(gè)網(wǎng)絡(luò)資源,由于網(wǎng)速比較慢,同步編程就意味著用戶必須等...

    曹金海 評(píng)論0 收藏0

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

0條評(píng)論

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