77
72

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

node.js Q 使い方 メモ

Posted at

node.jsでpromiseを使う機会があったので、自分のメモ用に残します。

Promiseって何?

Promiseって何よ?ってことで、まずはググる。

 Promiseとは非同期処理を上手く扱う為のAPIであり、パターンである。 
 非同期の処理の完了後に続けて処理を行いたいとき、よくコールバックパターンが使われるが、処理が連続するとコールバック地獄と言われる分かりづらいソースコードになってしまう。
 また、複数の非同期処理が完了した時に処理を行うなど、コールバックパターンでは難しい事をスマートにできるのがこのPromiseである。

要するに、同期処理したいけど、コールバック地獄で見づらくなるのを防ぐために使うAPIってことかな?

npmのパッケージとしては使用可能なモジュールはいくつかあるが、今回はQを使用する。

Q の基本 (.when .then .done)

簡単なQの記述は下記のようになる

var Q = require('q');

//非同期処理
var stepA = function(val) {
    var d = Q.defer();
    setTimeout(function(){
        console.log(val);
        d.resolve('fuga');
    }, 500);
    return d.promise
};

//同期処理
var stepB = function(val) {
    var d = Q.defer();
    console.log(val);
    d.resolve('piyo');
    return d.promise    
};

Q.when('hoge')
 .then(stepA)
 .then(stepB)
 .done(function(val){
    console.log(val);
});

下記はresult

hoge
fuga
piyo

Q.whenで最初の引数をset, .then(stepA)で、whenでsetした引数でstepAを呼び出し、d.resolveで次のメソッドへの引数をsetする。

.doneは最後に呼ばれる。

このようにPromiseを用いることで、同期・非同期に関係なく簡単に逐次処理を書くことが出来る。

forEachの処理 (.all)

下記の様な、forEachに対して、Promiseを用いる。

var func = function(val){
    //非同期処理
    setTimeout(function(){
        var result = val*val;
        d.resolve(result);
    }, 500);
    return result;
};

var arr = [1, 2, 3, 4, 5];

arr.forEach(function(val, index){
    result = func(val);
    console.log(result);
});

この場合、下記のように書く

var func = function(val){
    var d = Q.defer();
    //非同期処理
    setTimeout(function(){
        var result = val*val;
        d.resolve(result);
    }, 500);
    return d.promise;
};

var arr = [1, 2, 3, 4, 5];

Q.all(arr.map(func));
 .then(function(data){
    console.log(data);
 });

[ 1, 4, 9, 16, 25 ]

.allは、複数のメソッドを同時に実行して、全て完了したら、次の処理を行う。

.allと合わせてforEachのmapやreduceメソッドを使うことで、arrayの全要素に処理を行ってから、次の処理に移れる。

###.spread
.spreadは.allの処理全てが終わった後に実行される。この時、spreadで実行するメソッドの引数には、.allでresolveした値が入る。

.spreadを用いる場合、上記処理は下記のようになる。

var arr = [1, 2, 3, 4, 5];

Q.all(arr.map(func));
 .spread(function(res1, res2, res3, res4, res5){
    data = [res1, res2, res3, res4, res5];
    console.log(data);
 });

try-catch (.fail)

Qでは、.failを用いることで、ステップを途中で抜けることが出来る。

var stepA = function(val) {
    var d = Q.defer();
    setTimeout(function(){
        console.log("StepA:"+val);
        d.resolve('fuga');
    }, 500);
    return d.promise
};

var stepB = function(val) {
    var d = Q.defer();
    setTimeout(function(){
        console.log("StepB:"+val);
        d.reject('piyo');
    }, 500);
    return d.promise
};

var stepC = function(val) {
    var d = Q.defer();
    setTimeout(function(){
        console.log("StepC:"+val);
        d.resolve('hoge');
    }, 500);
    return d.promise
};

function QTest(){
  Q.when('hoge')
    .then(stepA)
    .then(stepB)
    .then(stepC)
    .fail(function(val){
      console.log("fail:"+val);
      var d = Q.defer();
      d.resolve('fail');
      return d.promise
    })
    .done(function(val){
      console.log("done:"+val);
    });
}

StepA:hoge
StepB:fuga
fail:piyo
done:fail

このように、ステップ内でrejectを検知したら、.failを実行してステップが終了する。

なお、failでステップを途中で抜けても、.doneは最後に必ず実行される。

77
72
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
77
72

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?