JavaScript中的非同步梳理(1)——使用訊息驅動

來源:互聯網
上載者:User

先舉一個例子,如果希望ABCDE這5個函數依次執行,我們可以寫出如下代碼。

A();B();C();D();E();

 

在同步的情況下,這樣的代碼沒有任何問題。但如果ABCDE都是非同步,還需要按次序執行,這樣寫就不行了。通常我們會為非同步函數設定回調,當函數執行完的時候執行回調,例如

A(function(){    B(function(){        C(function(){            D(function(){                E();            });        });    });});

毫無疑問這樣的編程體驗是很差的。當非同步流複雜的時候回調嵌套層數會很多,完全就是一場噩夢。

這還不是最重要的,如果想表達“當AB都完成的時候執行C”這樣的流程,並且希望A/B可以並行,就不能簡單的用這樣的回調了。
雖然說“當AB都完成的時候執行C”可以通過設定一個布爾量來解決,但是“當ABCD都完成的時候執行E”這樣的邏輯就需要在每個函數執行完的時候去判斷其他函數是否執行完,雖然的確是可行的,但是編程體現是比較差的。

身為一名懶惰的程式員,這樣顯然滿足不了我們的胃口。

@樸靈 寫了一個EventProxy,提供了事件驅動的非同步編程體驗

var proxy = new EventProxy();proxy.assign('A', function(){    B(function(){        proxy.trigger('B');    });});proxy.assign('B', function(){    C(function(){        proxy.trigger('C');    });});proxy.assign('C', function(){    D(function(){        proxy.trigger('D');    });});proxy.assign('D', function(){    E();});A(function(){    proxy.trigger('A');});

 可以看出通過訊息來驅動代碼可以讓非同步嵌套被“拉平”了,而如果要描述“當ABCD都完成的時候執行E”這樣的流程也很容易了

 

var proxy = new EventProxy();proxy.assign('A', 'B', 'C', 'D', E);A(function(){    proxy.trigger('A');});B(function(){    proxy.trigger('B');});C(function(){    proxy.trigger('C');});D(function(){    proxy.trigger('D');});

除了改善非同步編程體驗以外,EventProxy也可以提供一個自訂的事件系統。

EventProxy很簡單,原始碼只有300多行,但是對於我這樣的移動開發人員來說任何用不上的代碼都是負擔。
由於我自己將Event系統拆成了單獨的一個模組,而我(目前為止)也不需要EventProxy在trigger一個訊息的時候的參數傳遞的功能,對於some, any, not這些限定詞我也不需要,因此我自己實現了一個簡單版的非同步流量控制工具。

(function(export){var uid = 1;var Jas = function(){    this.map = {};    this.rmap = {};};var indexOf = Array.prototype.indexOf || function(obj){    for (var i=0, len=this.length; i<len; ++i){        if (this[i] === obj) return i;    }    return -1;};var fire = function(callback, thisObj){    setTimeout(function(){        callback.call(thisObj);    }, 0);};Jas.prototype = {    waitFor: function(resources, callback, thisObj){        var map = this.map, rmap = this.rmap;        if (typeof resources === 'string') resources = [resources];        var id = (uid++).toString(16); // using hex        map[id] = {            waiting: resources.slice(0), // clone Array            callback: callback,            thisObj: thisObj        };         for (var i=0, len=resources.length; i<len; ++i){            var res = resources[i],                list = rmap[res] || (rmap[res] = []);            list.push(id);        }        return this;    },    trigger: function(resources){        if (!resources) return this;        var map = this.map, rmap = this.rmap;        if (typeof resources === 'string') resources = [resources];        for (var i=0, len=resources.length; i<len; ++i){            var res = resources[i];            if (typeof rmap[res] === 'undefined') continue;            this._release(res, rmap[res]); // notify each callback waiting for this resource            delete rmap[res]; // release this resource        }        return this;    },    _release: function(res, list){        var map = this.map, rmap = this.rmap;        for (var i=0, len=list.length; i<len; ++i){            var uid = list[i], mapItem = map[uid], waiting = mapItem.waiting,                pos = indexOf.call(waiting, res);            waiting.splice(pos, 1); // remove            if (waiting.length === 0){ // no more depends                fire(mapItem.callback, mapItem.thisObj); // fire the callback asynchronously                delete map[uid];            }        }    }};export.Jas = Jas; // Jas is JavaScript Asynchronous (callings) Synchronizer})(window);

使用起來也挺簡單

var flow = new Jas();flow.waitFor(['A', 'B'], function(){    // both A and B are done!!}); $.getJSON(url1, function(data){    // An ajax request    flow.trigger('A');});$.getJSON(url2', function(data){    // Another ajax request    flow.trigger('B');});

小結一下:
使用訊息驅動的方式可以讓我們在非同步編程中避免一些回調嵌套的噩夢,最佳化編程體驗,在流程有修改的時候也更加靈活,可以用一種接近“聲明”式的方式去描述非同步函數流。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.