Node.js 中使用 Promise Q
27 Aug 2016假設我們要執行一項工作 task 3,但執行 task 3 之前要先依序完成工作 task 2 與 task 1。如果沒有使用 promise,而用 callback 的方式完成,程式碼大概會是這樣…
task1(function (value1) {
task2(value1, function(value2) {
task3(value2, function(value3) {
// do something with value3...
});
});
});
要做(依賴)的事情愈多,深度就愈深,完全就是 callback hell 了。
使用 Promise
承上,若使用 promise,只要等到目前的工作(task 1)完成,回傳一個訊息告知下一個工作(task 2) 可以開始動工,就解決這個 callback hell 的問題了。
var Q = require('q'), deferred = Q.defer();
function task1(value1) {
var response = "Complete task with " + value1;
deferred.resolve(response);
return deferred.promise;
}
function task2(value2) {
console.log(value2);
}
task1('Hello World').then(function(success) {
task2(success);
},function(error){
console.log(error);
},function(progress){
console.log(progress);
})
注意,回傳的 promise 有三種狀態
- 回傳成功:
deferred.resolve('resolve')
- 回傳失敗:
deferred.reject('reject')
- 回傳處理中:
deferred.notify('in progress')
為了舉例方便,範例只呈現了回傳成功的狀態。
結果
Complete task with Hello World
改寫前面依序執行三個工作(task 1、task 2與task 3)的 callback hell。
function task1(value){
var deferred = Q.defer(),
response = "Complete task" + value + " with Hello World" + value;
deferred.resolve(response);
return deferred.promise;
}
function task2(value){
var deferred = Q.defer(),
response = "Complete task" + value + " with Hello World" + value;
deferred.resolve(response);
return deferred.promise;
}
function task3(value){
var deferred = Q.defer(),
response = "Complete task" + value + " with Hello World" + value;
deferred.resolve(response);
return deferred.promise;
}
var promise1 = task1('1'), promise2, promise3;
promise2 = promise1.then(function(res) {
console.log(res);
return task2('2');
})
promise3 = promise2.then(function(res) {
console.log(res);
return task3('3');
})
promise3.then(function(res) {
console.log(res);
})
promise2 = promise1.then(function(res) {
console.log(res);
return task2('2');
})
簡化
由於 return 的值都是 promise,因此可以簡化成以下的樣子。
task1('1')
.then(function(res) {
console.log(res);
return task2('2');
})
.then(function(res) {
console.log(res);
return task3('3');
})
.done(function(res){
console.log(res);
});
結果
Complete task1 with Hello World1
Complete task2 with Hello World2
Complete task3 with Hello World3
Q.all[]
但若要等待多個工作呢?例如:等待 task 1 與 task 2(任意順序)完成後,再繼續完成 task 3。
var Q = require('q');
function task1(value1){
var response = "Complete task with " + value1,
deferred = Q.defer();
deferred.resolve(response);
return deferred.promise;
}
function task2(value2){
var response = "Complete task with " + value2,
deferred = Q.defer();
deferred.resolve(response);
return deferred.promise;
}
function task3(result1, result2) {
console.log(result1);
console.log(result2);
}
var value1 = "Hello",
value2 = "World",
promise = Q.all([task1(value1), task2(value2)]);
promise.then(function(results){
task3(results[0], results[1]);
})
將 taks 1 和 task 2 放到 Q.all[]
中,當 task 1 或 task 2 完成時,會回傳 promise。當 task 1 與 task 2 都回傳 promise 時,就會經由 promise.then()
執行接下來的工作,也就是 task 3。
結果
Complete task with Hello
Complete task with World
References
- kriskowal/q
- Promise - Q 函式庫
- Javascript - Promise, generator, async 與 ES6
- 在 Node.js 中使用 promise 擺脫回調金字塔
- 在 Node.js 中用 Q 實現 Promise – Callbacks 之外的另一種選擇
這篇文章的原始位置在這裡-Node.js 中使用 Promise Q
由於部落格搬遷至此,因此在這裡放了一份,以便閱讀;部份文章片段也做了些許修改,以期提供更好的內容。