ES6のプロミスがあるため、QやBlueBirdなどのプロミスライブラリを使用する理由はまだありますか?[閉まっている]


228

Node.jsがpromiseのネイティブサポートを追加した後も、QやBlueBirdなどのライブラリを使用する理由はまだありますか?

たとえば、新しいプロジェクトを開始していて、このプロジェクトでこれらのライブラリを使用する依存関係がないと仮定すると、そのようなライブラリを使用する理由は本当にないと言えますか?


4
ネイティブプロミスには非常に基本的な機能があります。QやBluebirdのようなライブラリは、さらに多くを追加します。これらの機能が必要な場合は、それらのライブラリを使用してください。
gman

7
タイトルを編集して、「必要性」ではなく、「promiseライブラリを引き続き使用する理由」を強調しました。この質問には、意見ではなく事実を主に提供することで回答できます。それは主に意見ではなく事実を提供することで答えることができるので、再開する必要があります。そのデモンストレーションとして以下の回答を参照してください。
jfriend00

11
@JaromandaX-タイトルと質問が調整され、Promiseライブラリの使用が「必要」であるかどうかではなく、Promiseライブラリを使用する理由について詳しく説明されたので、再開することを検討してください。私の意見では、この質問は、主に意見ではなく、事実を提供することで回答できます。その実証として、以下の回答を参照してください。
jfriend00 2016年

6
タイトル編集後のこの質問、およびその受け入れられた回答は、意見に基づくものではありません。
最大

7
同意した。これは、現在の形では完全に有効な質問です。再開を指名しました。
ジュール

回答:


367

古い格言は、あなたは仕事に適したツールを選ぶべきだと言っています。ES6 promiseは基本を提供します。あなたが望むか必要とするすべてが基本であるなら、それはあなたのためにうまくいくはずです/できます。ただし、ツールビンには、基本的なツールよりも多くのツールがあり、それらの追加のツールが非常に役立つ状況があります。また、ES6のプロミスには、ほぼすべてのnode.jsプロジェクトで役立つpromisificationなどの基本的な要素が欠けていることもあります。

私はBluebird promiseライブラリに最も精通しているので、そのライブラリでの私の経験から主に話をします。

それで、より有能なPromiseライブラリを使用する理由のトップ6を次に示します

  1. インタフェース非同期非Promisified - .promisify()とは、.promisifyAll()1行のコードは、インターフェース全体のpromisifiedバージョンを作成します-まだ平野コールバックを必要とし、まだ約束を返さないすべてのそれらの非同期インターフェースを処理するのに非常に便利です。

  2. より高速 -Bluebirdは、ほとんどの環境でネイティブの約束より大幅に高速です。

  3. 非同期配列反復のシーケンス - Promise.mapSeries()またはPromise.reduce()、配列を反復処理して、各要素で非同期操作を呼び出しますが、非同期操作を順番に実行するので、すべてが同時に発生するわけではありません。これを行うことができるのは、宛先サーバーが要求するため、または1つの結果を次の結果に渡す必要があるためです。

  4. ポリフィル -古いバージョンのブラウザクライアントでpromiseを使用する場合は、とにかくポリフィルが必要です。可能性のあるポリフィルも入手できます。node.jsにはES6のプロミスがあるため、node.jsにポリフィルは必要ありませんが、ブラウザで可能です。node.jsサーバーとクライアントの両方をコーディングする場合、両方に同じpromiseライブラリと機能を含めると非常に便利です(コードの共有、環境間のコンテキスト切り替え、非同期コードの一般的なコーディング手法の使用など)。 。)。

  5. その他の便利な機能 -ブルーバードがありPromise.map()Promise.some()Promise.any()Promise.filter()Promise.each()およびPromise.props()すべてのは時折便利です。これらの操作はES6のプロミスと追加のコードで実行できますが、Bluebirdにはこれらの操作が事前にビルドおよびテストされているため、使用するコードがよりシンプルで少なくなります。

  6. 組み込みの警告と完全なスタックトレース -Bluebirdには、おそらく間違ったコードまたはバグである問題を警告する組み込みの警告がいくつかあります。たとえば、.then()そのプロミスを返さずにハンドラ内に新しいプロミスを作成する関数を呼び出す場合(現在のプロミスチェーンにリンクするため)、ほとんどの場合、それは偶然のバグであり、Bluebirdは警告を表示します効果。その他の組み込みのBluebird警告は、ここで説明されています

これらのさまざまなトピックの詳細は次のとおりです。

PromisifyAll

どのnode.jsプロジェクトでも、.promisifyAll()モジュールのような標準のnode.jsモジュールで多く使用するため、どこでもすぐにBluebirdを使用しfsます。

Node.js自体は、fs モジュールのように非同期IOを行う組み込みモジュールへのpromiseインターフェースを提供しません。したがって、これらのインターフェイスでpromiseを使用する場合は、使用する各モジュール関数の周囲にpromiseラッパーを手動でコーディングするか、promiseを使用するか使用しないライブラリを取得するかを選択できます。

ブルーバードのPromise.promisify()Promise.promisifyAll()の約束を返すために大会の非同期APIを呼び出すのNode.jsの自動折り返しを提供しています。非常に便利で時間を節約できます。いつも使っています。

これがどのように機能するかの例です:

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

fs.readFileAsync('somefile.text').then(function(data) {
   // do something with data here
});

代わりにfs、使用したいAPI ごとに独自のpromiseラッパーを手動で作成することもできます。

const fs = require('fs');

function readFileAsync(file, options) {
    return new Promise(function(resolve, reject) {
        fs.readFile(file, options, function(err, data) {
            if (err) {
                reject(err);
            } else {
                 resolve(data);
            }
        });
    });
}

readFileAsync('somefile.text').then(function(data) {
   // do something with data here
});

また、使用するAPI関数ごとに手動でこれを行う必要があります。これは明らかに意味がありません。それは定型コードです。また、これを行うユーティリティを入手することもできます。Bluebird's Promise.promisify()and Promise.promisifyAll()はそのようなユーティリティです。

その他の便利な機能

以下は、私が特に便利だと思うBluebirdの機能の一部です(これらがコードを節約したり、開発をスピードアップしたりする方法について、以下にいくつかのコード例があります)。

Promise.promisify()
Promise.promisifyAll()
Promise.map()
Promise.reduce()
Promise.mapSeries()
Promise.delay()

その便利な機能にPromise.map()加えて、同時に実行できる操作の数を指定できる同時実行オプションもサポートします。これは、実行することがたくさんあるが、外部を圧倒できない場合に特に便利です。資源。

これらの一部は、スタンドアロンと呼ばれることも、それ自体が反復可能コードに解決されて多くのコードを節約できるpromiseで使用されることもあります。


ポリフィル

ブラウザプロジェクトでは、Promiseをサポートしていない一部のブラウザを引き続きサポートしたいので、とにかくポリフィルが必要になります。jQueryも使用している場合は、jQueryに組み込まれているpromiseサポートを使用することもできます(ただし、いくつかの点でひどく非標準であり、おそらくjQuery 3.0で修正されています)。ただし、プロジェクトに重要な非同期アクティビティが含まれている場合は、 Bluebirdの拡張機能は非常に便利です。


もっと早く

また、BluebirdのPromiseは、V8に組み込まれているPromiseよりも大幅に高速であるように見えます。そのトピックの詳細については、この投稿を参照してください。


大きなものNode.jsがありません

node.js開発でBluebirdをあまり使用しないことを検討する理由は、node.jsがpromisify関数を組み込んでいるため、次のようなことができるということです。

const fs = requirep('fs');

fs.readFileAsync('somefile.text').then(function(data) {
   // do something with data here
});

または、組み込みモジュールの一部としてすでに約束された方法を提供するだけです。

それまでは、Bluebirdでこれを行います。

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

fs.readFileAsync('somefile.text').then(function(data) {
   // do something with data here
});

ES6のpromiseサポートがnode.jsに組み込まれていて、組み込みモジュールのどれもpromiseを返さないのは少し奇妙に思われます。これは、node.jsで整理する必要があります。それまでは、Bluebirdを使用してライブラリ全体を約束します。つまり、組み込みモジュールのいずれも手動で最初にラッピングせずにプロミスを使用できないため、promiseはnode.jsに約20%実装されているように感じられます。


これが単純なPromiseとBluebirdの約束の例でありPromise.map()、ファイルのセットを並行して読み取り、すべてのデータの処理が完了したときに通知する例です。

明白な約束

const files = ["file1.txt", "fileA.txt", "fileB.txt"];
const fs = require('fs');

// make promise version of fs.readFile()
function fsReadFileP(file, options) {
    return new Promise(function(resolve, reject) {
        fs.readFile(file, options, function(err, data) {
            if (err) return reject(err);
            resolve(data);
        });
    });
}


Promise.all(files.map(fsReadFileP)).then(function(results) {
    // files data in results Array
}, function(err) {
    // error here
});

ブルーバードPromise.map()Promise.promisifyAll()

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));
const files = ["file1.txt", "fileA.txt", "fileB.txt"];

Promise.map(files, fs.readFileAsync).then(function(results) {
    // files data in results Array
}, function(err) {
    // error here
});

以下は、単純なPromiseとBluebirdの約束の例でありPromise.map()、一度に4つまで読み取ることができるが、できるだけ多くの要求を並行して保持したいリモートホストから一連のURLを読み取る場合の例です。

明白なJSの約束

const request = require('request');
const urls = [url1, url2, url3, url4, url5, ....];

// make promisified version of request.get()
function requestGetP(url) {
    return new Promise(function(resolve, reject) {
        request.get(url, function(err, data) {
            if (err) return reject(err);
            resolve(data);
        });
    });
}

function getURLs(urlArray, concurrentLimit) {
    var numInFlight = 0;
    var index = 0;
    var results = new Array(urlArray.length);
    return new Promise(function(resolve, reject) {
        function next() {
            // load more until concurrentLimit is reached or until we got to the last one
            while (numInFlight < concurrentLimit && index < urlArray.length) {
                (function(i) {
                    requestGetP(urlArray[index++]).then(function(data) {
                        --numInFlight;
                        results[i] = data;
                        next();
                    }, function(err) {
                        reject(err);
                    });
                    ++numInFlight;
                })(index);
            }
            // since we always call next() upon completion of a request, we can test here
            // to see if there was nothing left to do or finish
            if (numInFlight === 0 && index === urlArray.length) {
                resolve(results);
            }
        }
        next();
    });
}

ブルーバードプロミス

const Promise = require('bluebird');
const request = Promise.promisifyAll(require('request'));
const urls = [url1, url2, url3, url4, url5, ....];

Promise.map(urls, request.getAsync, {concurrency: 4}).then(function(results) {
    // urls fetched in order in results Array
}, function(err) {
    // error here
});

それは痛いですが、いくつかの点で非標準 - -彼らは今、「約束/ A +互換性」:)であることを主張するblog.jquery.com/2016/01/14/jquery-3-0-beta-released
thefourtheye

1
@thefourtheye-はい、私は彼らが3.0でPromise / A +互換性に向けて取り組んできたことを知っています。しかし、それはまだベータ版です。プロミス(しゃれた意図)に従っている場合、すでにjQueryを使用している場合は、ブラウザのJSで外部プロミスライブラリを使用する理由の一部が取り除かれる可能性があります。それでも、Bluebirdが提供するすべての便利な機能を備えているわけではありません。Bluebirdのパフォーマンスに見合った機能を備えている場合は非常に驚かれるので、場合によっては将来のjQueryとともにBluebirdの余地があります。いずれにせよ、OPの質問は主にnode.jsに関するもののようです。
jfriend00

1
最後のコード例には少しタイプミスがありますreturn new Promise(function(resolve, rejct)。する必要があります:reject
セバスチャンMuszyński

7
Node.jsには実際にはutil.promisify現在ありますが、直接対応promisifyAllするものはありません。
nyuszika7h 2017

1
@Aurast-はい、v11が対応しますがfs、Bluebirdを使用する他のいくつかの理由(私の特定のお気に入りはのconcurrencyオプションですPromise.map())で、多数の並列リクエストを行う必要があるターゲットサービスを圧倒しないようにします。また、BluebirdのpromisifyAllを使用するために、他の多くの約束されていないインターフェースがまだあります。しかし、node.js自体が組み込みのpromiseサポートを強化するにつれて、新しいプロジェクトごとにBluebirdをすぐに入手する理由は徐々に消えていきます。
jfriend00
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.