Apakah masih ada alasan untuk menggunakan perpustakaan janji seperti Q atau BlueBird sekarang karena kami memiliki janji ES6? [Tutup]

228

Setelah Node.js menambahkan dukungan asli untuk janji, apakah masih ada alasan untuk menggunakan perpustakaan seperti Q atau BlueBird?

Misalnya jika Anda memulai proyek baru dan mari kita asumsikan dalam proyek ini Anda tidak memiliki dependensi yang menggunakan pustaka ini, dapatkah kita mengatakan bahwa sebenarnya tidak ada lagi alasan untuk menggunakan pustaka seperti itu?

Murat Ozgul
sumber
4
janji asli memiliki fitur yang sangat mendasar. Perpustakaan seperti Q atau Bluebird menambahkan banyak lagi. Jika Anda membutuhkan fitur-fitur tersebut maka gunakan pustaka tersebut.
gman
7
Saya mengedit judul untuk membuatnya lebih sedikit tentang "perlu" dan lebih banyak tentang "alasan untuk tetap menggunakan perpustakaan janji". Pertanyaan ini dapat dijawab dengan memberikan fakta, bukan pendapat. Ini harus dibuka kembali karena dapat dijawab dengan memberikan fakta dan bukan hanya pendapat. Lihat jawaban di bawah ini sebagai demonstrasi dari itu.
jfriend00
11
@JaromandaX - Harap pertimbangkan pembukaan kembali sekarang karena judul dan pertanyaan telah diubah untuk lebih tentang mengapa seseorang akan menggunakan perpustakaan janji daripada apakah seseorang "perlu" untuk menggunakan perpustakaan janji. Menurut pendapat saya, pertanyaan ini dapat dijawab dengan memberikan fakta dan bukan terutama pendapat - lihat jawaban di bawah ini sebagai demonstrasi dari itu.
jfriend00
6
Pertanyaan ini setelah pengeditan judul, dan jawaban yang diterima, tidak berdasarkan pendapat.
maks
7
Sepakat. Ini adalah pertanyaan yang benar-benar valid dalam bentuknya saat ini. Saya telah mencalonkan untuk membuka kembali.
Jules

Jawaban:

367

Pepatah lama mengatakan bahwa Anda harus memilih alat yang tepat untuk pekerjaan itu. ES6 berjanji memberikan dasar-dasar. Jika semua yang Anda inginkan atau butuhkan adalah dasar-dasarnya, maka itu seharusnya bisa bekerja dengan baik untuk Anda. Tapi, ada lebih banyak alat di dalam bin alat daripada hanya dasar-dasarnya dan ada situasi di mana alat-alat tambahan sangat berguna. Dan, saya berpendapat bahwa janji ES6 bahkan kehilangan beberapa dasar-dasar seperti promisifikasi yang berguna di hampir setiap proyek node.js.

Saya paling akrab dengan perpustakaan janji Bluebird jadi saya akan berbicara sebagian besar dari pengalaman saya dengan perpustakaan itu.

Jadi, inilah 6 alasan utama saya untuk menggunakan perpustakaan Promise yang lebih mampu

  1. Antarmuka async yang non-Promisified - .promisify()dan .promisifyAll()sangat berguna untuk menangani semua antarmuka async yang masih membutuhkan panggilan balik biasa dan belum mengembalikan janji - satu baris kode menciptakan versi yang dipatenkan dari seluruh antarmuka.

  2. Lebih cepat - Bluebird secara signifikan lebih cepat daripada janji asli di sebagian besar lingkungan.

  3. Mengurutkan pengulangan array async - Promise.mapSeries()atau Promise.reduce()memungkinkan Anda untuk beralih melalui sebuah array, memanggil operasi async pada setiap elemen, tetapi mengurutkan operasi async sehingga mereka terjadi satu demi satu, tidak semua pada waktu yang sama. Anda dapat melakukan ini karena server tujuan memerlukannya atau karena Anda harus meneruskan satu hasil ke yang berikutnya.

  4. Polyfill - Jika Anda ingin menggunakan janji di versi klien browser yang lebih lama, Anda tetap akan memerlukan polyfill. Semoga juga mendapatkan polyfill yang mumpuni. Karena node.js memiliki janji ES6, Anda tidak perlu polyfill di node.js, tetapi Anda bisa menggunakan browser. Jika Anda mengkode server dan klien node.js, mungkin sangat berguna untuk memiliki perpustakaan janji dan fitur yang sama di keduanya (lebih mudah untuk berbagi kode, konteks beralih antar lingkungan, menggunakan teknik pengkodean umum untuk kode async, dll. .).

  5. Fitur yang berguna lainnya - Bluebird memiliki Promise.map(), Promise.some(), Promise.any(), Promise.filter(), Promise.each()dan Promise.props()semua yang kadang-kadang berguna. Sementara operasi ini dapat dilakukan dengan janji-janji ES6 dan kode tambahan, Bluebird datang dengan operasi-operasi ini yang sudah pra-dibangun dan pra-diuji sehingga lebih mudah dan lebih sedikit kode untuk menggunakannya.

  6. Peringatan bawaan dan Jejak Tumpukan Penuh - Bluebird memiliki sejumlah peringatan bawaan yang mengingatkan Anda akan masalah yang mungkin salah kode atau bug. Misalnya, jika Anda memanggil fungsi yang membuat janji baru di dalam .then()handler tanpa mengembalikan janji itu (untuk menautkannya ke rantai janji saat ini), maka dalam kebanyakan kasus, itu adalah bug yang tidak disengaja dan Bluebird akan memberi Anda peringatan untuk itu efek. Peringatan Bluebird built-in lainnya dijelaskan di sini .

Berikut ini beberapa detail tentang berbagai topik ini:

Promisikan Semua

Dalam setiap proyek node.js, saya segera menggunakan Bluebird di mana-mana karena saya menggunakan .promisifyAll()banyak pada modul node.js standar seperti fsmodul.

Node.js sendiri tidak menyediakan antarmuka janji untuk modul built-in yang melakukan Iyn seperti fs modul. Jadi, jika Anda ingin menggunakan janji dengan antarmuka tersebut, Anda dibiarkan menggunakan kode tangan sebagai pembungkus janji untuk setiap fungsi modul yang Anda gunakan atau mendapatkan perpustakaan yang bisa melakukan itu untuk Anda atau tidak menggunakan janji.

Bluebird Promise.promisify()dan Promise.promisifyAll()menyediakan pembungkus otomatis node.js yang memanggil API async konvensi untuk mengembalikan janji. Ini sangat berguna dan menghemat waktu. Saya menggunakannya sepanjang waktu.

Berikut ini contoh cara kerjanya:

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

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

Alternatifnya adalah dengan membuat pembungkus janji Anda sendiri untuk setiap fsAPI yang ingin Anda gunakan:

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
});

Dan, Anda harus melakukan ini secara manual untuk setiap fungsi API yang ingin Anda gunakan. Ini jelas tidak masuk akal. Ini kode boilerplate. Anda mungkin juga mendapatkan utilitas yang berfungsi untuk Anda. Bluebird Promise.promisify()dan Promise.promisifyAll()utilitas seperti itu.

Fitur Berguna Lainnya

Berikut adalah beberapa fitur Bluebird yang menurut saya berguna (ada beberapa contoh kode di bawah ini tentang bagaimana ini dapat menyimpan kode atau mempercepat pengembangan):

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

Selain fungsinya yang bermanfaat, Promise.map()juga mendukung opsi konkurensi yang memungkinkan Anda menentukan berapa banyak operasi yang boleh dijalankan pada saat yang sama yang sangat berguna ketika Anda memiliki banyak hal yang harus dilakukan, tetapi tidak dapat membanjiri beberapa di luar sumber.

Beberapa di antaranya dapat disebut stand-alone dan digunakan berdasarkan janji yang dengan sendirinya berubah menjadi iterable yang dapat menyimpan banyak kode.


Polyfill

Dalam proyek peramban, karena Anda umumnya ingin tetap mendukung beberapa peramban yang tidak memiliki dukungan Janji, Anda tetap memerlukan polyfill. Jika Anda juga menggunakan jQuery, kadang-kadang Anda bisa menggunakan janji dukungan yang dibangun ke dalam jQuery (meskipun sangat tidak standar dalam beberapa hal, mungkin diperbaiki di jQuery 3.0), tetapi jika proyek tersebut melibatkan aktivitas async yang signifikan, saya menemukan fitur-fitur yang diperluas di Bluebird sangat berguna.


Lebih cepat

Juga patut dicatat bahwa janji-janji Bluebird tampaknya jauh lebih cepat daripada janji-janji yang tertanam dalam V8. Lihat posting ini untuk diskusi lebih lanjut tentang topik itu.


A Big Thing Node.js is Missing

Apa yang akan membuat saya mempertimbangkan untuk menggunakan Bluebird lebih sedikit dalam pengembangan node.js adalah jika node.js dibangun dalam fungsi yang menjanjikan sehingga Anda dapat melakukan sesuatu seperti ini:

const fs = requirep('fs');

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

Atau hanya menawarkan metode yang sudah dijanjikan sebagai bagian dari modul bawaan.

Sampai saat itu, saya melakukan ini dengan Bluebird:

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

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

Tampaknya agak aneh untuk memiliki dukungan ES6 janji yang dibangun ke node.js dan tidak memiliki modul built-in yang mengembalikan janji. Ini perlu disortir dalam node.js. Sampai saat itu, saya menggunakan Bluebird untuk menjanjikan seluruh perpustakaan. Jadi, rasanya seperti janji-janji sekitar 20% diimplementasikan di node.js sekarang karena tidak ada modul built-in yang memungkinkan Anda menggunakan janji-janji tanpa membungkusnya terlebih dahulu secara manual.


Contohnya

Berikut adalah contoh Promises vs Bluebird yang jelas dan Promise.map()untuk membaca sekumpulan file secara paralel dan memberi tahu ketika dilakukan dengan semua data:

Janji Biasa

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
});

Bluebird Promise.map()danPromise.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
});

Berikut adalah contoh Promises vs Bluebird yang jelas dan Promise.map()ketika membaca sekelompok URL dari host jarak jauh tempat Anda dapat membaca paling banyak 4 sekaligus, tetapi ingin menyimpan sebanyak mungkin permintaan secara paralel sesuai yang diizinkan:

Janji JS Biasa

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();
    });
}

Janji Bluebird

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
});
pacar00
sumber
meskipun sangat tidak standar dalam beberapa hal - Mereka mengklaim bahwa mereka "Janji / A + kompatibel" sekarang :) - blog.jquery.com/2016/01/14/jquery-3-0-beta-released
thefourtheye
1
@thefourtheye - Ya, saya tahu mereka telah bekerja menuju kompatibilitas Promise / A + di 3.0. Tapi, itu masih dalam versi beta. Jika memenuhi janji (pun intended), itu mungkin meniadakan beberapa alasan untuk menggunakan perpustakaan janji eksternal di browser JS jika Anda sudah menggunakan jQuery. Ini masih tidak memiliki semua fitur berguna yang Bluebird lakukan dan saya akan sangat terkejut jika itu sesuai dengan kinerja Bluebird sehingga masih ada ruang untuk Bluebird bersama jQuery masa depan dalam beberapa kasus. Bagaimanapun, pertanyaan OP sebagian besar tentang node.js.
jfriend00
1
Ada kesalahan ketik kecil dalam contoh kode terakhir: return new Promise(function(resolve, rejct). Harus:reject
Sebastian Muszyński
7
Node.js sebenarnya sudah ada util.promisifysekarang, meskipun tidak ada promisifyAllpadanan langsung .
nyuszika7h
1
@Urast - Ya, v11 menangani fs, tetapi masih ada beberapa alasan lain untuk menggunakan Bluebird (favorit khusus saya adalah concurrencypilihan untuk Promise.map()) agar tidak membanjiri layanan target yang Anda perlukan untuk membuat banyak permintaan paralel. Juga, masih banyak antarmuka lain yang tidak diizinkan untuk menggunakan Bluebird's promisifyAll with. Tapi, perlahan-lahan alasan untuk segera meraih Bluebird di setiap proyek baru memudar sebagai node.js sendiri menambah dukungan janji bawaannya.
jfriend00