Apakah itu Janji ES6 atau Janji burung biru, Janji Q, dll.
Bagaimana cara saya menguji untuk melihat apakah objek yang diberikan adalah Janji?
javascript
promise
q
bluebird
es6-promise
theram
sumber
sumber
.then
metode, tetapi itu tidak akan memberi tahu Anda apa yang Anda miliki adalah Janji yang pasti. Yang Anda tahu pada saat itu adalah bahwa Anda memiliki sesuatu yang memperlihatkan.then
metode, seperti Janji..then
Maksud saya adalah bahwa siapa pun dapat membuat objek yang memaparkan metode yang bukan Janji, tidak berperilaku seperti Janji dan tidak punya niat untuk digunakan seperti Janji. Memeriksa.then
metode hanya memberi tahu Anda bahwa jika objek tidak memiliki.then
metode, maka Anda tidak memiliki Janji. Terbalik - bahwa adanya.then
metode berarti bahwa Anda lakukan memiliki Janji - belum tentu benar..then
metode. Ya, itu memiliki potensi positif palsu, tetapi asumsi bahwa semua perpustakaan janji mengandalkan (karena hanya itu yang bisa mereka andalkan). Satu-satunya alternatif sejauh yang saya lihat adalah mengambil saran Benjamin Gruenbaum dan menjalankannya melalui test suite janji. Tetapi itu tidak praktis untuk kode produksi aktual.Jawaban:
Bagaimana perpustakaan janji memutuskan
Jika memiliki
.then
fungsi - itulah satu - satunya perpustakaan janji standar yang digunakan.Spesifikasi Janji / A + memiliki gagasan yang disebut
then
mampu yang pada dasarnya adalah "objek denganthen
metode". Janji akan dan harus mengasimilasi apa pun dengan metode saat itu. Semua implementasi janji yang Anda sebutkan melakukan ini.Jika kita melihat spesifikasinya :
Ini juga menjelaskan alasan untuk keputusan desain ini:
Bagaimana Anda harus memutuskan
Anda seharusnya tidak - alih-alih menelepon
Promise.resolve(x)
(Q(x)
dalam Q) yang akan selalu mengonversi nilai apa pun atau eksternal yangthen
dapat menjadi janji tepercaya. Ini lebih aman dan lebih mudah daripada melakukan pemeriksaan ini sendiri.benar - benar harus yakin?
Anda selalu dapat menjalankannya melalui test suite : D
sumber
Memeriksa apakah ada sesuatu yang dijanjikan tidak perlu mempersulit kode, cukup gunakan
Promise.resolve
sumber
Inilah jawaban asli saya, yang sejak itu telah diratifikasi dalam spesifikasi sebagai cara untuk menguji janji:
Ini berfungsi karena algoritma secara eksplisit menuntut bahwa
Promise.resolve
harus mengembalikan objek tepat yang dilewatkan jika dan hanya jika itu adalah janji dengan definisi spesifikasi.Saya punya jawaban lain di sini, yang dulu mengatakan ini, tetapi saya mengubahnya ke sesuatu yang lain ketika tidak bekerja dengan Safari pada waktu itu. Itu setahun yang lalu, dan ini sekarang bekerja dengan baik bahkan di Safari.
Saya akan mengedit jawaban asli saya, kecuali yang terasa salah, mengingat bahwa lebih banyak orang sekarang telah memilih solusi yang diubah dalam jawaban itu daripada yang asli. Saya percaya ini adalah jawaban yang lebih baik, dan saya harap Anda setuju.
sumber
===
bukan==
?Pembaruan: Ini bukan lagi jawaban terbaik. Harap pilih jawaban saya yang lain sebagai gantinya.
harus melakukannya. Perhatikan bahwa ini hanya dapat bekerja dengan andal dengan janji ES6 asli.
Jika Anda menggunakan shim, perpustakaan janji, atau apa pun yang berpura-pura seperti janji, maka mungkin lebih tepat untuk menguji "layak" (apa pun dengan
.then
metode), seperti yang ditunjukkan dalam jawaban lain di sini.sumber
Promise.resolve(obj) == obj
tidak akan berfungsi di Safari. Gunakaninstanceof Promise
sebagai gantinya.obj && typeof obj.then == 'function'
, karena itu akan bekerja dengan semua jenis janji dan sebenarnya cara yang direkomendasikan oleh spesifikasi dan digunakan oleh implementasi / polyfill. NativePromise.all
misalnya akan bekerja pada semua kemampuanthen
, tidak hanya janji asli lainnya. Begitu juga kode Anda. Jadiinstanceof Promise
bukan solusi yang baik.console.log(typeof p, p, p instanceof Promise);
menghasilkan output ini:object Promise { <pending> } false
. Seperti yang Anda lihat itu adalah janji baik-baik saja - namuninstanceof Promise
tes kembalifalse
?sumber
Untuk melihat apakah objek yang diberikan adalah Janji ES6 , kita dapat menggunakan predikat ini:
Call
ingtoString
langsung dariObject.prototype
mengembalikan representasi string asli dari jenis objek yang diberikan"[object Promise]"
dalam kasus kami. Ini memastikan objek yang diberikantoString
Metode yang ditulis sendiri dari objek yang diberikan.instanceof
atauisPrototypeOf
.Namun, objek host tertentu apa pun , yang tagnya dimodifikasi melalui
Symbol.toStringTag
, dapat kembali"[object Promise]"
. Ini mungkin hasil yang dimaksudkan atau tidak tergantung pada proyek (misalnya jika ada implementasi Janji kustom).Untuk melihat apakah objek tersebut berasal dari Promise ES6 asli , kita dapat menggunakan:
Menurut ini dan bagian ini dari spec, representasi string dari fungsi harus:
yang ditangani sesuai di atas. The FunctionBody adalah
[native code]
di semua browser utama.MDN:
Function.prototype.toString
Ini berfungsi di berbagai konteks lingkungan juga.
sumber
Bukan jawaban untuk pertanyaan lengkap tapi saya pikir layak untuk menyebutkan bahwa di Node.js 10
isPromise
ditambahkan fungsi util yang ditambahkan yang memeriksa apakah suatu objek adalah Janji asli atau tidak:sumber
Beginilah cara paket graphql-js mendeteksi janji:
value
adalah nilai yang dikembalikan dari fungsi Anda. Saya menggunakan kode ini dalam proyek saya dan sejauh ini tidak ada masalah.sumber
Ini formulir kode https://github.com/ssnau/xkit/blob/master/util/is-promise.js
jika suatu objek dengan suatu
then
metode, itu harus diperlakukan sebagai aPromise
.sumber
Jika Anda menggunakan TypeScript , saya ingin menambahkan bahwa Anda dapat menggunakan fitur "type predicate". Hanya harus membungkus verifikasi logis dalam fungsi yang mengembalikan
x is Promise<any>
dan Anda tidak perlu melakukan typecast. Di bawah ini pada contoh saya,c
adalah janji atau salah satu dari tipe saya yang ingin saya ubah menjadi janji dengan memanggilc.fetch()
metode.Info lebih lanjut: https://www.typescriptlang.org/docs/handbook/advanced-types.html
sumber
Jika Anda menggunakan metode async, Anda dapat melakukan ini dan menghindari ambiguitas.
Jika fungsi mengembalikan janji, itu akan menunggu dan kembali dengan nilai yang diselesaikan. Jika fungsi mengembalikan nilai, itu akan diperlakukan sebagai diselesaikan.
Jika fungsi tidak mengembalikan janji hari ini, tetapi besok mengembalikan satu atau dinyatakan async, Anda akan menjadi bukti di masa depan.
sumber
Promise.resolve()
sumber
Saya menggunakan fungsi ini sebagai solusi universal:
sumber
setelah mencari cara yang dapat diandalkan untuk mendeteksi fungsi Async atau bahkan Janji , saya akhirnya menggunakan tes berikut:
sumber
Promise
membuat subkelas dan membuat instance dari itu, tes ini bisa gagal. ini seharusnya bekerja untuk sebagian besar dari apa yang Anda coba untuk menguji.fn.constructor.name === 'AsyncFunction'
salah - itu berarti ada sesuatu yang merupakan fungsi async dan bukan janji - juga itu tidak dijamin untuk bekerja karena orang-orang dapat mensubclass janjiES6:
sumber
toString
metode hanya dapat mengembalikan string yang menyertakan"Promise"
.'NotAPromise'.toString().includes('Promise') === true