工做告一段落,閒來無事,寫了一個在nodejs實現「半阻塞」的控制程序。javascript
一直以來,nodejs以單線程非阻塞,高併發的特性而聞名。搞這個「半阻塞」是東西,有什麼用呢?java
場景一:node
如今的web應用可有都是一個這樣的結構:git
http服務(node) > 接口(業務邏輯) > 數據庫github
不少時候,瓶頸通常出如今業務層,或者數據層。更多的多是某一個業務的處理,拉下整個系統的性能。web
當用戶或一些不懷好意的人,故意大量調用這些處理邏輯,好吧,你nodejs是非阻塞的,這一大波處理請求就一窩蜂衝到到業務層,極可能致使整個系統性能降低,或者癱瘓。數據庫
若是這個時候,node層就把這些耗資源的請求,排好隊,控制好併發,甚至分用戶排成隊,配置好不一樣身份的用戶併發量。是否是很好。npm
場景二:api
應用中,可能會有一些無需即時處理的同一類業務,處理前都須要收集一次資源,處理業務,處理後再清理一次。高消耗工做主要在收集或是清理上。promise
這個時候,咱們可將要處理的業務暫存到隊列中,當隊列數量到達一個值或是某個時間點時,咱們一次性處理完隊列中的任務。在消耗上,只作一次「收集」、「清理」的操做。
可見,若是在小型的項目中若是node方便實現相似線程池的功能,對整個項目的穩定性及工做效率是有很大貢獻的。
如今說一說我寫的這一個「半阻塞」的東西,爲何要基於Promise;
若是你用過q.js或瞭解EC6,應該對Promise有所瞭解,否則還請先了解下。
個人想法是,並不須要把整個業務的後續處理全都放到隊列中去,而只是將高消耗的那一部分放入隊列,利用Promise的異部處理機制來處理後續的操做。
在編寫代碼的時候你幾乎能夠忘記隊列的存在,可是他就在那裏默默的工做着,代碼可讀性和靈活性沒有絲毫影響。
queue-fun 是基於Promise的 運行隊列控制類。
初始化隊列控制 參數q可傳
push
unshift
go
jump
返回對應的promisevar queue = new queue-fun.Queue()(100,{ "event_succ":function(){} //成功 ,"event_err":function(){} //失敗 ,"event_begin":function(){} //隊列開始 ,"event_end":function(){} //隊列完成 ,"event_add":function(){} //有執行項添加進執行單元后執行,注意go及jump不會觸發 ,"retryON":0 //隊列單元出錯重試次數 ,"retryType":0 //重試模式true/false(優先/擱置)執行 })`
向隊列中尾部添加運行單元 fun: promise function args: 傳入的參數 con 默認值
{
'event_succ':null //通常沒用,某些狀況下,可能比then要方便 ,'event_err':null //通常沒用,某些狀況下,可能比then要方便 ,'Queue_event':true //默認會執行隊列定義的回調 }
修改並行數
啓動隊列
暫停隊列
清空隊列
var queuefun = require('queue-fun'); //引入 //初始化Promise異步隊列類 var Queue = queuefun.Queue(); //實列化最大併發爲2的運行隊列 var queue1 = new Queue(2,{ "event_succ":function(data){console.log('queue-succ:',data)} //成功 ,"event_err":function(err){console.log('queue-succ:',data)} //失敗 }); var q = queuefun.Q; //模塊中簡單實現了Q的基本功能,能夠一試, //定義一個Promise風格的異步方法 function testfun(i){ var deferred = q.defer(); setTimeout(function(){ if(i\ && i % 3 == 0){ deferred.reject(new Error("err " + i)) }else{ deferred.resolve(i) } },(Math.random() * 2000)>>0) return deferred.promise; } //向隊列添加運行單元 queue1.push(testfun,[1]) //添加運行項 queue1.go(testfun,[2]) //添加並自動啓動隊列 queue1.go(testfun,[3],{Queue_event:0}) //添加不會觸發隊列 回調的運行項. queue1.go(testfun,[4]).then( function(data){console.log('done-succ:',data)}, function(err){console.log('done-err:',err)} ) queue1.go(testfun,[5],{ event_succ:function(data){console.log('conf-succ:',data)}, event_err:function(err){console.log('conf-err:',err)} })
實現了Promises/A+規範及done
,spread
,fail
;
API模仿Q;
模擬實現了 q.defer
,q.Promise
,q.all
,q.any
,q.nfcall
,q.nfapply
,q.denodeify
等函數.
若是你習慣了.then風格寫代碼,你能夠嘗試用toPromis將普通函數/語句包裝一下,讓他能夠得到then方法,及捕獲錯誤。
var add = function(a,b){return a+b;} q.toPromis(function(){return add(a+b)}) .then(console.log,console.error)
安裝:npm install quque-fun