Node.js 中使用 Promise Q

在 Node.js 中使用 Promise Q

假設我們今天要執行一項工作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


由於部落格搬家了,因此在新落格也放了一份,未來若有增刪會在這裡更新-Node.js 中使用 Promise Q

留言