情報アイランド

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

Node.jsで非同期コールバック関数を引数として受け取る関数をプロミスに変換する

非同期コールバック関数を引数として受け取る関数をプロミスに変換するにはプロミスクラスのdenodeify関数かpromisify関数かfromNode関数かnfcall関数を使用します。

denodeify関数は下のプロミスクラスで提供されています。

  • promiseクラス
  • q.Promiseクラス
var promise = require('promise');

var fp = promise.denodeify(function (arg1, arg2, callback) {
    callback(null, 'xxx');
    //or
    callback(new Error('yyy'), null);
});

promisify関数は下のプロミスクラスで提供されています。

  • bluebirdクラス
var bluebird = require('bluebird');

var fp = bluebird.promisify(function (arg1, arg2, callback) {
    callback(null, 'xxx');
    //or
    callback(new Error('yyy'), null);
});

第1引数に非同期コールバック関数を引数として受け取る関数を指定します。

返り値としてプロミスを返す関数が得られます。この関数の引数は第1引数の関数の最後の引数以外の引数と同じになります。

そのため、この関数を呼び出すと返り値としてプロミスが得られます。

var p = fp('aaa', 'bbb');

fromNode関数は下のプロミスクラスで提供されています。

  • bluebirdクラス
var bluebird = require('bluebird');

var p = bluebird.fromNode(function (callback) {
    callback(null, 'xxx');
    //or
    callback(new Error('yyy'), null);
});

第1引数に非同期コールバック関数を引数として受け取る関数を指定します。

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

nfcall関数は下のプロミスクラスで提供されています(ただし、qモジュールの場合、q.nfcall関数となります)。

  • q.Promiseクラス
var q = require('q');

var p = q.nfcall(function (arg1, arg2, callback) {
    callback(null, 'xxx');
    //or
    callback(new Error('yyy'), null);
}, 'aaa', 'bbb');

第1引数に非同期コールバック関数を引数として受け取る関数を指定します。

第2引数以降に第1引数の関数の最後の引数以外の引数を指定します。

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

サンプルコード1

別の記事で作成したpromise-then-2.js(→複数のプロミスを連結する)をpromise.denodeify関数を使用するように書き換えたものです。

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

promise-denodeify.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 = promise.denodeify(fs.stat)(process.argv[2]).then(function (stats) {
    if (stats.isFile()) {
        return { size: stats.size };
    }
    else {
        throw new Error('not a file.');
    }
});

var p2 = p.then(function (result) {
    return promise.denodeify(fs.readFile)(process.argv[2], 'utf-8').then(function (data) {
        result.data = data;
        return 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-denodeify.js promise-denodeify.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 = promise.denodeify(fs.stat)(process.argv[2]).then(function (stats) {
        if (stats.isFile()) {
                return { size: stats.size };
        }
        else {
                throw new Error('not file.');
        }
});

var p2 = p.then(function (result) {
        return promise.denodeify(fs.readFile)(process.argv[2], 'utf-8').then(function (data) {
                result.data = data;
                return 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: 983
size: 983
hash: 06ddfdb8bbdc62cdbf16ce7ef5598b565275af7def6141e73045d085448a83b1

関連

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

-Node.js