javascript 多線程異步隊列


首先,你得知道 jQuery.Deferred 的大致用法,然后,我們進入正題吧:

庫代碼:

/*!
 * 多線程異步隊列
 * 依賴 jQuery 1.8+ (如果你用的是 1.6或1.7, 只要將源碼中的 then方法替換為pipe方法 即可)
 */

/**
 * @n {Number} 正整數, 線程數量
 */
function Queue (n) {
    n = parseInt(n, 10);
    return new Queue.prototype.init( (n && n > 0) ? n : 1 )
}

Queue.prototype = {
    init: function (n) {
        this.threads = [];
        this.taskList = [];

        while (n--) {
            this.threads.push(new this.Thread)
        }
    },

    /**
     * @callback {Fucntion} promise對象done時的回調函數,它的返回值必須是一個promise對象
     */
    push: function (callback) {
        if (typeof callback !== 'function') return;

        var index = this.indexOfIdle();

        if (index != -1) {
            this.threads[index].idle(callback)
            try { console.log('Thread-' + (index+1) + ' accept the task!') } catch (e) {}
        }
        else {
            this.taskList.push(callback);

            for (var i = 0, l = this.threads.length; i < l; i++) {

                (function(thread, self, id){
                    thread.idle(function(){
                        if (self.taskList.length > 0) {
                            try { console.log('Thread-' + (id+1) + ' accept the task!') } catch (e) {}

                            var promise = self.taskList.shift()();    // 正確的返回值應該是一個promise對象
                            return promise.promise ? promise : $.Deferred().resolve().promise();
                        } else {
                            return $.Deferred().resolve().promise();
                        }
                    })
                })(this.threads[i], this, i);

            }
        }
    },
    indexOfIdle: function () {
        var threads = this.threads,
            thread = null,
            index = -1;

        for (var i = 0, l = threads.length; i < l; i++) {
            thread = threads[i];

            if (thread.promise.state() === 'resolved') {
                index = i;
                break;
            }
        }

        return index;
    },
    Thread: function () {
        this.promise = $.Deferred().resolve().promise();

        this.idle = function (callback) {
            this.promise = this.promise.then(callback)
        }
    }
};

Queue.prototype.init.prototype = Queue.prototype;

使用示例:

    var queue = new Queue(3);    // 創建一個具有3個線程的隊列

  // task-1 queue.push(
function(){ var defer = $.Deferred(); setTimeout(function(){ defer.resolve() }, 8000); return defer.promise() })
  // task-2 queue.push(
function(){ var defer = $.Deferred(); setTimeout(function(){ defer.resolve() }, 2000); return defer.promise() })
  // task-3 queue.push(
function(){ var defer = $.Deferred(); setTimeout(function(){ defer.resolve() }, 6000); return defer.promise() })
  // task-4 queue.push(
function(){ var defer = $.Deferred(); setTimeout(function(){ defer.resolve() }, 3000); return defer.promise() })
  // task-5 queue.push(
function(){ var defer = $.Deferred(); setTimeout(function(){ defer.resolve() }, 2000); return defer.promise() })
  // task-6 queue.push(
function(){ var defer = $.Deferred(); setTimeout(function(){ defer.resolve() }, 2000); return defer.promise() })

控制台有顯示 queue.push的 function (暫且叫它task)  最終是哪個進程處理的

實例化后,隊列里的3個線程都是處於空閑狀態的
將task-1分配給線程1, 這個任務耗時 8s
將task-2分配給線程2, 這個任務耗時 2s
將task-3分配給線程3, 這個任務耗時 6s

因為當前沒有空閑進程,隊列內部則將task-4、task-5、task-6添加到等候區

因為task-2耗時2s,進程2最先被解放,然后task-4就被分配到進程2去處理,以此類推,最后控制台顯示的進程使用情況是:1、2、3、2、2、3

 

這個庫的使用場景是這樣的
1、如本人最近做的項目:
主播在做直播,很多觀眾會給主播送禮物,這些禮物都是有js動畫特效的,頁面中最多可以同時顯示三個禮物特效

2、相互依賴的異步請求
a請求依賴b請求,b請求依賴c請求,c請求依賴。。。
這個需求我們就可以使用這個庫這樣實現:

var queue = new Queue(1);

// request c
queue.push(function(){
    return $.ajax();    // jq 的ajax返回的正是 promise對象
})

// request b
queue.push(function(){
    return $.ajax();
})

// request a
queue.push(function(){
    return $.ajax();
})

 queue.push(callback)   callback必須返回一個promise對象



 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM