情報アイランド

「情報を制する者は世界を制す」をモットーに様々な情報を提供することを目指すブログです。現在はプログラミング関連情報が多めですが、投資関連情報も取り扱っていきたいです。

Node.jsで複数のプロミスを連結する

2016/09/02

p.then関数

プロミスが保留状態から完了状態やエラー状態に変わった後に更に別の非同期的な処理を行う新しいプロミスを作成するにはp.then関数を使用します。

p.then関数は全てのプロミスクラスで提供されています。

var p = p.then(function (result) {
    return 'xxx';
    //or
    return new promise(function (resolve, reject) {
        //...
    });
    //or
    throw new err;
}, function (err) {
    return 'yyy';
    //or
    return new promise(function (resolve, reject) {
        //...
    });
    //or
    throw new err;
});

第1引数にプロミスが保留状態から完了状態に変わった場合に非同期的に呼び出される関数を指定します。この関数の第1引数は結果です。

第2引数にプロミスが保留状態からエラー状態に変わった場合に非同期的に呼び出される関数を指定します。この関数の第1引数はエラーオブジェクトです。この引数は指定しなくても構いません。

第1引数と第2引数の関数では返り値として新しいプロミスの結果を返すようにします。

あるいは、結果を返す代わりに別のプロミスを返すこともできます。この場合、別のプロミスに処理を移譲することができます。

なお、これらの関数の実行中に例外が発生した場合には新しいプロミスは保留状態からエラー状態に変わります。

返り値として新しいプロミスが得られます。

これにより、複数の非同期的な処理を連結することができます

p.catch関数

p.catch(onRejected)p.then(null, onRejected)と同じになります。

p.catch関数は全てのプロミスクラスで提供されています。

var p = p.catch(function (err) {
    return 'xxx';
    //or
    return new promise(function (resolve, reject) {
        //...
    });
    //or
    throw new err;
});

サンプルコード1

p.then関数の使用例です。

promise-then-1.js

var promise = require('promise');

if (process.argv.length < 3) {
    console.error('lack argument.');
    process.exit(1);
}

var p = new promise(function (resolve, reject) {
    var n = Number(process.argv[2]);
    if (n || n === 0) {
        resolve(n);
    }
    else {
        throw new Error('not a number.');
    }
});

var pt1 = p.then(function (result) {
    if (result % 2 === 0) {
        return result / 2;
    }
    else {
        throw new Error('not divisible by 2.');
    }
});

var pt2 = pt1.then(function (result) {
    if (result % 3 === 0) {
        return result / 3;
    }
    else {
        throw new Error('not divisible by 3.');
    }
});

pt2.done(function (result) {
    console.log('result is ' + result + '.');
}, function (err) {
    console.error(err);
    process.exit(1);
});

使用パッケージ

  • promise
    npm install promiseでインストールします。

実行結果

C:\work\node>node promise-then-1.js 0
result is 0.

C:\work\node>node promise-then-1.js 2
Error: not divisible by 3.
    at C:\work\node\promise-then-1.js:32:9
    at tryCallOne (C:\work\node\node_modules\promise\lib\core.js:37:12)
    at C:\work\node\node_modules\promise\lib\core.js:123:15
    at flush (C:\work\node\node_modules\asap\raw.js:50:29)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickCallback (internal/process/next_tick.js:98:9)
    at Function.Module.runMain (module.js:577:11)
    at startup (node.js:159:18)
    at node.js:444:3

C:\work\node>node promise-then-1.js 3
Error: not divisible by 2.
    at C:\work\node\promise-then-1.js:23:9
    at tryCallOne (C:\work\node\node_modules\promise\lib\core.js:37:12)
    at C:\work\node\node_modules\promise\lib\core.js:123:15
    at flush (C:\work\node\node_modules\asap\raw.js:50:29)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickCallback (internal/process/next_tick.js:98:9)
    at Function.Module.runMain (module.js:577:11)
    at startup (node.js:159:18)
    at node.js:444:3

C:\work\node>node promise-then-1.js 6
result is 1.

サンプルコード2

コマンドライン引数として与えられたテキストファイルのデータ、文字数、ファイルサイズ、SHA-256のハッシュ値を標準出力に出力します。

promise-then-2.js

var promise = require('promise');
var fs = require('fs');
var crypto = require('crypto');

if (process.argv.length < 3) {
    console.error('lack argument.');
    process.exit(1);
}

var p = new promise(function (resolve, reject) {
    fs.stat(process.argv[2], function (err, stats) {
        if (err) {
            reject(err);
        }
        else if (stats.isFile()) {
            resolve({ size: stats.size });
        }
        else {
            reject(new Error('not a file.'));
        }
    });
});

var p2 = p.then(function (result) {
    return new promise(function (resolve, reject) {
        fs.readFile(process.argv[2], 'utf-8', function (err, data) {
            if (err) {
                reject(err);
            }
            else {
                result.data = data;
                resolve(result);
            }
        });
    });
});

var p3 = p2.then(function (result) {
    var hash = crypto.createHash('sha256');
    hash.update(result.data);
    result.hash = hash.digest('hex');
    return result;
});

p3.done(function (result) {
    console.log('data: ' + result.data);
    console.log('length: ' + result.data.length);
    console.log('size: ' + result.size);
    console.log('hash: ' + result.hash);
}, function (err) {
    console.error(err);
    process.exit(1);
});

使用パッケージ

  • promise
    npm install promiseでインストールします。

実行結果

C:\work\node>node promise-then-2.js promise-then-2.js
data: var promise = require('promise');
var fs = require('fs');
var crypto = require('crypto');

if (process.argv.length < 3) {
        console.error('lack argument.');
        process.exit(1);
}

var p = new promise(function (resolve, reject) {
        fs.stat(process.argv[2], function (err, stats) {
                if (err) {
                        reject(err);
                }
                else if (stats.isFile()) {
                        resolve({ size: stats.size });
                }
                else {
                        reject('not file.');
                }
        });
});

var p2 = p.then(function (result) {
        return new promise(function (resolve, reject) {
                fs.readFile(process.argv[2], 'utf-8', function (err, data) {
                        if (err) {
                                reject(err);
                        }
                        else {
                                result.data = data;
                                resolve(result);
                        }
                });
        });
});

var p3 = p2.then(function (result) {
        var hash = crypto.createHash('sha256');
        hash.update(result.data);
        result.hash = hash.digest('hex');
        return result;
});

p3.done(function (result) {
        console.log('data: ' + result.data);
        console.log('length: ' + result.data.length);
        console.log('size: ' + result.size);
        console.log('hash: ' + result.hash);
}, function (err) {
        console.error(err);
        process.exit(1);
});
length: 1147
size: 1147
hash: fe60560715ca63effb4e3035bbdceb52dc83ccdd02956743d5f695539d4e2046

関連

pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-Node.js