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对象