Apa antipattern konstruksi janji eksplisit dan bagaimana cara menghindarinya?

May 22 2014

Saya sedang menulis kode yang melakukan sesuatu yang terlihat seperti:

function getStuffDone(param) {           | function getStuffDone(param) {
    var d = Q.defer(); /* or $q.defer */ |     return new Promise(function(resolve, reject) {
    // or = new $.Deferred() etc.        |     // using a promise constructor
    myPromiseFn(param+1)                 |         myPromiseFn(param+1)
    .then(function(val) { /* or .done */ |         .then(function(val) {
        d.resolve(val);                  |             resolve(val);
    }).catch(function(err) { /* .fail */ |         }).catch(function(err) {
        d.reject(err);                   |             reject(err);
    });                                  |         });
    return d.promise; /* or promise() */ |     });
}                                        | }

Seseorang mengatakan kepada saya bahwa ini disebut " antipattern yang ditangguhkan " atau " Promiseantipattern konstruktor ", apa yang buruk tentang kode ini dan mengapa ini disebut antipattern ?

Jawaban

380 BenjaminGruenbaum May 22 2014 at 17:07

The antipattern ditangguhkan (sekarang eksplisit-konstruksi antipattern) diciptakan oleh Esailija adalah orang antipattern umum yang baru untuk janji membuat, saya telah membuat sendiri ketika saya pertama kali digunakan janji. Masalah dengan kode di atas adalah gagal memanfaatkan fakta bahwa rantai janji.

Janji dapat berantai .thendan Anda dapat membalas janji secara langsung. Kode Anda di getStuffDonedapat ditulis ulang sebagai:

function getStuffDone(param){
    return myPromiseFn(param+1); // much nicer, right?
}

Janji adalah tentang membuat kode asinkron lebih mudah dibaca dan berperilaku seperti kode sinkron tanpa menyembunyikan fakta tersebut. Janji mewakili abstraksi atas nilai operasi satu kali, janji tersebut mengabstraksi gagasan pernyataan atau ekspresi dalam bahasa pemrograman.

Anda sebaiknya hanya menggunakan objek yang ditangguhkan saat Anda mengonversi API menjadi promise dan tidak dapat melakukannya secara otomatis, atau saat Anda menulis fungsi agregasi yang lebih mudah diungkapkan dengan cara ini.

Mengutip Esailija:

Ini adalah anti-pola yang paling umum. Sangat mudah untuk jatuh ke dalam hal ini jika Anda tidak benar-benar memahami promise dan menganggapnya sebagai pemancar acara atau utilitas panggilan balik yang dimuliakan. Mari kita rekap: janji adalah tentang membuat kode asinkron mempertahankan sebagian besar properti kode sinkron yang hilang seperti indentasi datar dan satu saluran pengecualian.

142 Bergi Aug 29 2014 at 20:28

Apakah ada yang salah?

Tapi polanya berhasil!

Beruntungnya kamu. Sayangnya, mungkin tidak, karena Anda mungkin lupa beberapa casing edge. Di lebih dari setengah kejadian yang pernah saya lihat, penulis lupa untuk menangani penanganan kesalahan:

return new Promise(function(resolve) {
    getOtherPromise().then(function(result) {
        resolve(result.property.example);
    });
})

Jika janji lain ditolak, ini akan terjadi tanpa diketahui alih-alih disebarkan ke janji baru (di mana janji itu akan ditangani) - dan janji baru tetap menunggu selamanya, yang dapat menyebabkan kebocoran.

Hal yang sama terjadi jika kode panggilan balik Anda menyebabkan kesalahan - misalnya ketika resulttidak memiliki propertydan pengecualian dilempar. Itu akan tidak tertangani dan membuat janji baru tidak terselesaikan.

Sebaliknya, penggunaan .then()secara otomatis menangani kedua skenario ini, dan menolak janji baru saat terjadi kesalahan:

 return getOtherPromise().then(function(result) {
     return result.property.example;
 })

Antipattern yang ditangguhkan tidak hanya rumit, tetapi juga rawan kesalahan . Menggunakan .then()untuk rantai jauh lebih aman.

Tapi saya sudah menangani semuanya!

Betulkah? Baik. Namun, ini akan sangat mendetail dan berlebihan, terutama jika Anda menggunakan library promise yang mendukung fitur lain seperti pembatalan atau penyampaian pesan. Atau mungkin di masa mendatang, atau Anda ingin menukar perpustakaan Anda dengan yang lebih baik? Anda tidak akan ingin menulis ulang kode Anda untuk itu.

Metode perpustakaan ( then) tidak hanya secara asli mendukung semua fitur, mereka juga mungkin memiliki pengoptimalan tertentu pada tempatnya. Menggunakannya kemungkinan akan membuat kode Anda lebih cepat, atau setidaknya memungkinkan untuk dioptimalkan dengan revisi perpustakaan di masa mendatang.

Bagaimana cara menghindarinya?

Jadi, setiap kali Anda menemukan diri Anda secara manual membuat Promiseatau Deferreddan janji yang sudah ada terlibat, periksa API perpustakaan terlebih dahulu . Antipattern yang ditangguhkan sering diterapkan oleh orang-orang yang melihat janji [hanya] sebagai pola pengamat - tetapi janji lebih dari sekadar panggilan balik : janji itu seharusnya dapat disusun. Setiap perpustakaan yang layak memiliki banyak fungsi yang mudah digunakan untuk menyusun janji dengan segala cara yang dapat dipikirkan, mengurus semua hal tingkat rendah yang tidak ingin Anda tangani.

Jika Anda merasa perlu membuat beberapa promise dengan cara baru yang tidak didukung oleh fungsi helper yang ada, menulis fungsi Anda sendiri dengan Deferreds yang tidak dapat dihindari harus menjadi pilihan terakhir Anda. Pertimbangkan untuk beralih ke perpustakaan yang lebih berfitur, dan / atau laporkan bug ke perpustakaan Anda saat ini. Pemelihara harus dapat memperoleh komposisi dari fungsi yang ada, mengimplementasikan fungsi pembantu baru untuk Anda dan / atau membantu mengidentifikasi kasus tepi yang perlu ditangani.