Apa pola yang benar untuk Promise.defer?

Saya menggunakan TypeScript dan async/await untuk mewakili alur kerja asinkron. Bagian dari alur kerja tersebut adalah memanggil pekerja web dan melanjutkan ketika pekerja tersebut memanggil kembali dengan hasil.

Di C#, saya akan membuat TaskCompletionSource, await dengan Task dan di tempat lain dalam kode akan memanggil SetResult untuk menyelesaikan TaskCompletionSource.

Saya dapat melakukan hal yang sama dalam JavaScript dengan menginisialisasi objek Deferrer menggunakan Promise.defer(), awaiting Promise dan di tempat lain, di window.onmessage pendengar akan memanggil metode resolve (atau reject) untuk membiarkan alur kerja asinkron berlanjut.

Kedengarannya bagus, tapi MDN mengatakan defer sudah usang. Solusi yang diusulkan menggunakan konstruktor Promise yang membuat delegasi melakukan pekerjaan dan memanggil metode resolve/reject tidak berfungsi untuk saya, karena logika itu mungkin di luar jangkauan saya, saya hanya ingin objek memanggil resolve atau reject aktif dalam lingkup leksikal yang sama sekali berbeda, saya tidak bisa melakukan itu dengan fungsi itu.

Ada Pembantu yang kompatibel dengan maju dan mundur yang memberi saya objek seperti itu dengan mengikat fungsi resolve dan reject yang dapat saya gunakan tanpa mengubah semantik kode saya. Namun apakah ini praktik yang buruk? Apakah ada pola yang dikenal dan lebih baik? Apa persamaan idiomatik dari TaskCompletionSource dalam JavaScript?


person Tomáš Hübelbauer    schedule 01.08.2016    source sumber


Jawaban (1)


Sama sekali tidak ada yang salah dengan penolong yang melakukan penangguhan selama Anda yakin memang membutuhkan penangguhan. Dalam semua pemrograman janji saya, saya hanya menemukan satu situasi di mana saya benar-benar memerlukan penundaan dan tidak bisa begitu saja merestrukturisasi kode saya untuk menggunakan pola konstruktor Promise yang khas.

Tampaknya situasi yang saya temukan dan yang ditunjukkan orang lain terjadi ketika Anda memiliki pemisahan antara kode yang membuat objek janji/penangguhan dan kode yang menyelesaikan atau menolaknya. Biasanya, Anda memilikinya bersama-sama, namun terkadang ada bagian kode yang benar-benar berbeda dan ada alasan logis untuk melakukannya seperti itu. Dalam kasus tersebut, objek yang ditangguhkan yang dibangun berdasarkan janji reguler dapat menjadi metode implementasi yang lebih bersih.

Berikut implementasi Deferred sederhana lainnya yang juga kompatibel ke belakang dan ke depan:

Mengapa konstruktor Promise memerlukan eksekutor?

Namun apakah ini praktik yang buruk?

Saya tahu ada beberapa orang puritan di luar sana yang berpikir Anda tidak boleh melakukan ini. Namun, menurut saya ini adalah praktik yang sangat bagus jika Anda yakin bahwa ini adalah cara paling bersih dan paling sederhana untuk mengimplementasikan kode Anda dan mengimplementasikannya dengan callback eksekutor konstruktor Promise yang khas tidaklah praktis. Ada orang-orang yang ingin menggunakan deferred bahkan tanpa mencoba atau mempelajari konstruktor/pelaksana janji dan itu bukan praktik yang baik. Karena berbagai alasan, konstruktor janji harus digunakan jika praktis.

Salah satu alasan utama mengapa konstruktor janji lebih disukai adalah karena semua kode khusus janji dalam fungsi panggilan balik pelaksana bersifat "aman". Jika pengecualian dimasukkan ke dalam kode itu, maka secara otomatis akan ditangkap dan menolak janji (yang merupakan hal yang baik). Setelah Anda menggunakan deferred dan memiliki banyak kode yang memanipulasi janji di luar panggilan balik itu, itu tidak secara otomatis aman untuk dibuang. Faktanya, kode Anda bahkan dapat muncul secara serempak yang merupakan mimpi buruk bagi penelepon untuk dilindungi. Anda dapat melihat deskripsi masalah tersebut di sini: https://stackoverflow.com/a/37657831/816620. Jadi, pola yang ditangguhkan tidak disukai, namun dengan perlindungan yang tepat, masih ada beberapa kasus (umumnya jarang terjadi) yang mengarah pada penerapan yang lebih bersih.

Apakah ada pola yang dikenal dan lebih baik?

Jawabannya kurang lebih sama seperti di atas. Preferensinya adalah menggunakan konstruktor/pelaksana janji, tetapi dalam situasi di mana hal itu tidak praktis (biasanya ketika bagian kode yang berbeda membuat janji dan kemudian menyelesaikan/menolaknya) dan tidak ada cara sederhana untuk mengatur ulang kode agar berfungsi dengan baik konstruktor/pelaksana janji, maka objek yang ditangguhkan kemungkinan merupakan implementasi yang lebih disukai. Biasanya Anda akan menemukan situasi tersebut jarang terjadi karena sebagian besar waktu Anda dapat menyusun kode Anda sehingga potongan kode yang sama membuat dan menyelesaikan/menolak janji dan Anda tidak memerlukan penundaan.

Apa persamaan idiomatis dari TaskCompletionSource di JavaScript?

Tidak ada padanan bawaan dalam Javascript. Oleh karena itu, Anda harus membuatnya sendiri dan sepertinya janji adalah cara alami untuk melakukannya karena janji tersebut secara alami dibuat untuk menandakan penyelesaian atau kesalahan. Anda harus menunjukkan kepada kami kode Anda yang sebenarnya agar kami dapat memberikan pendapat tentang apakah situasi spesifik Anda dapat diimplementasikan dengan baik tanpa menggunakan objek yang ditangguhkan.

person jfriend00    schedule 01.08.2016
comment
Ini adalah jawaban yang luar biasa, terima kasih telah meluangkan banyak waktu untuk itu. Saya tidak dapat membayangkan bagaimana saya akan membuat Promise untuk menunggu di jendela utama dan resolve dari pekerja web (file yang berbeda!) saat menggunakan eksekutor konstruktor Promise, jadi menurut saya Saya baik-baik saja menggunakan Deferred untuk ini. - person Tomáš Hübelbauer; 02.08.2016
comment
@TomášHübelbauer - Ya, webWorker pada akhirnya harus mengirim pesan ke thread utama untuk berkomunikasi dengannya, bukan? Bisakah Anda meminta pelaksana janji mendengarkan pesan itu dan menyelesaikan janji di pelaksana ketika menerima pesan? Saya hanya menebak-nebak di sini karena saya belum melihat kode Anda yang sebenarnya. - person jfriend00; 02.08.2016
comment
Kalau dipikir-pikir, saya bisa mendengarkan pesan dalam implementasi eksekutor, meskipun saat ini pemroses pesan saya berada di tempat terpusat dan dengan cara ini saya harus membaginya ke setiap eksekutor. Saya akan bermain-main dengannya, mungkin saya mengabaikan sesuatu. Akan mengirimkan pertanyaan jika saya kehabisan ide atau tidak yakin. :) - person Tomáš Hübelbauer; 02.08.2016
comment
@TomášHübelbauer - Seringkali (meskipun tidak selalu) pola desain pelaksana hanya memerlukan pemikiran ulang tentang bagaimana kode disusun untuk memanfaatkannya. Semoga beruntung. - person jfriend00; 02.08.2016
comment
Saya selalu menghindarinya karena saya membuat fungsi callback di setiap fungsi. jshint memperingatkan untuk tidak membuat fungsi secara dinamis. Bukankah ini masalah kinerja yang besar? Itukah sebabnya lebih disukai menggunakan new Promise(callback) saja? - person Noitidart; 19.08.2016
comment
@Noitidart - Menurut pendapat saya, jshint menyebabkan Anda menghindari cara coding yang lebih baik. Pemeriksa kode ini sebenarnya cukup bodoh. Jika Anda secara membabi buta melakukan apa yang mereka katakan, dalam beberapa kasus Anda akan menyimpang dari praktik terbaik. Anda harus tahu apa yang Anda lakukan dan kapan harus mengabaikannya. Fungsi inline anonim sangat berguna dalam Javascript dan jelas merupakan cara terbaik untuk menulis beberapa kode. Saya tidak akan menghindarinya. jsHint mungkin hanya mengeluh jika Anda melakukan itu berulang kali sehingga saya harus melihat kode persisnya untuk mengetahui apa yang saya rekomendasikan. - person jfriend00; 19.08.2016