Saya telah membaca tentang jQuery ditangguhkan dan janji dan saya tidak bisa melihat perbedaan antara menggunakan .then()
& .done()
untuk panggilan balik yang sukses. Saya tahu Eric Hynds menyebutkan itu .done()
dan .success()
memetakan ke fungsi yang sama tapi saya kira begitu juga .then()
karena semua panggilan balik semua dipanggil pada penyelesaian operasi yang sukses.
Adakah yang bisa tolong beri tahu saya tentang penggunaan yang benar?
jquery
promise
jquery-deferred
screenm0nkey
sumber
sumber
Jawaban:
Callback yang dilampirkan
done()
akan dipecat ketika ditangguhkan diselesaikan. Callback yang dilampirkanfail()
akan dipecat ketika ditangguhkan ditolak.Sebelum jQuery 1.8,
then()
itu hanya gula sintaksis:Pada 1,8,
then()
adalah alias untukpipe()
dan mengembalikan janji baru, lihat di sini untuk informasi lebih lanjut tentangpipe()
.success()
danerror()
hanya tersedia padajqXHR
objek yang dikembalikan oleh panggilan keajax()
. Itu adalah alias sederhana untukdone()
danfail()
masing - masing:Selain itu,
done()
tidak terbatas pada panggilan balik tunggal dan akan memfilter non-fungsi (meskipun ada bug dengan string di versi 1.8 yang harus diperbaiki di 1.8.1):Sama berlaku untuk
fail()
.sumber
then
mengembalikan janji baru adalah hal kunci yang saya lewatkan. Saya tidak bisa mengerti mengapa rantai seperti$.get(....).done(function(data1) { return $.get(...) }).done(function(data2) { ... })
gagal dengandata2
tidak terdefinisi; ketika aku berubahdone
untukthen
bekerja, karena saya benar-benar ingin janji-janji pipa bersama-sama daripada melampirkan lebih penangan untuk janji aslinya.done
atauthen
? Mengapa?.then()
).Ada juga perbedaan dalam cara pengembalian hasil diproses (disebut chaining,
done
tidak berantai saatthen
menghasilkan rantai panggilan)Hasil berikut akan dicatat:
Sementara
akan mendapatkan yang berikut ini:
---------- Perbarui:
Btw. Saya lupa menyebutkan, jika Anda mengembalikan Janji bukan nilai jenis atom, janji luar akan menunggu sampai janji dalam diselesaikan:
dengan cara ini menjadi sangat mudah untuk menyusun operasi asinkron paralel atau berurutan seperti:
Kode di atas mengeluarkan dua permintaan http secara paralel sehingga membuat permintaan selesai lebih cepat, sementara di bawah permintaan http tersebut dijalankan secara berurutan sehingga mengurangi beban server
sumber
done
tidak melakukan apa pun terhadap hasil yangthen
mengubah hasilnya. Poin besar yang terlewatkan oleh yang lain imo.then
berubah dalam 1,8done
danthen
hasil panggilan masukdone
contohnya. Ubahthen
kepipe
dalam pra-1.8 untuk mendapatkanthen
perilaku 1.8+ ..done()
hanya memiliki satu panggilan balik dan itu adalah panggilan balik yang berhasil.then()
memiliki panggilan balik sukses dan gagal.fail()
hanya memiliki satu panggilan balik yang gagaljadi terserah Anda apa yang harus Anda lakukan ... apakah Anda peduli apakah itu berhasil atau jika gagal?
sumber
then()
sangat berbedadone()
. Sepertithen()
yang sering dipanggil hanya dengan panggilan balik sukses poin Anda lebih merupakan detail daripada hal utama yang perlu diingat / diketahui. (Tidak bisa mengatakan bagaimana keadaannya sebelum jQuery 3.0.)deferred.done ()
menambahkan penangan untuk dipanggil hanya ketika Ditangguhkan diselesaikan . Anda dapat menambahkan beberapa panggilan balik untuk dipanggil.
Anda juga dapat menulis di atas seperti ini,
deferred.then ()
menambahkan penangan yang akan dipanggil ketika Ditangguhkan diselesaikan, ditolak atau masih dalam proses .
sumber
then
berperilaku jika tidak adafail
panggilan balik yang disediakan - yaitu tidak menangkapfail
kasus sama sekaliSebenarnya ada perbedaan yang cukup penting, sejauh jQuery's Deferreds dimaksudkan untuk menjadi implementasi dari Janji (dan jQuery3.0 benar-benar mencoba untuk membawanya ke dalam spesifikasi).
Perbedaan utama antara dilakukan / kemudian adalah itu
.done()
SELALU mengembalikan nilai Janji / terbungkus yang sama dengan yang dimulainya, terlepas dari apa yang Anda lakukan atau apa yang Anda kembalikan..then()
selalu mengembalikan Janji BARU, dan Anda bertanggung jawab untuk mengendalikan apa yang dijanjikan berdasarkan pada fungsi yang Anda berikan untuk mengembalikannya.Diterjemahkan dari jQuery ke ES2015 Promises asli,
.done()
adalah semacam menerapkan struktur "ketuk" di sekitar fungsi dalam rantai Janji, dalam hal itu akan, jika rantai tersebut dalam keadaan "tekad", berikan nilai ke fungsi. ... tetapi hasil dari fungsi itu TIDAK akan mempengaruhi rantai itu sendiri.Keduanya akan log 5, bukan 6.
Perhatikan bahwa saya menggunakan done dan doneWrap untuk melakukan logging, bukan .then. Itu karena fungsi console.log tidak benar-benar mengembalikan apa pun. Dan apa yang terjadi jika Anda lulus. Lalu fungsi yang tidak mengembalikan apa pun?
Itu akan masuk:
Apa yang terjadi? Ketika saya menggunakan .then dan meneruskannya fungsi yang tidak mengembalikan apa pun, hasilnya implisit adalah "tidak terdefinisi" ... yang tentu saja mengembalikan Janji [tidak terdefinisi] ke metode selanjutnya, yang dicatat tidak terdefinisi. Jadi nilai awal yang kami mulai pada dasarnya hilang.
.then()
pada dasarnya adalah bentuk komposisi fungsi: hasil dari setiap langkah digunakan sebagai argumen untuk fungsi di langkah berikutnya. Karena itulah .done dianggap sebagai "tap" -> itu sebenarnya bukan bagian dari komposisi, hanya sesuatu yang menyelinap melihat nilai pada langkah tertentu dan menjalankan fungsi pada nilai itu, tetapi tidak benar-benar mengubah komposisi dengan cara apa pun.Ini adalah perbedaan yang cukup mendasar, dan mungkin ada alasan bagus mengapa Janji asli tidak memiliki metode .done dilaksanakan sendiri. Kita tidak harus membahas mengapa tidak ada metode .fail, karena itu bahkan lebih rumit (yaitu, .fail / .catch BUKAN mirror dari fungsi .done / .then -> dalam .catch yang mengembalikan nilai telanjang tidak menghasilkan "tetap" ditolak seperti yang diteruskan. lalu, mereka menyelesaikan!)
sumber
then()
selalu berarti itu akan dipanggil dalam kasus apa pun. Tetapi parameter yang lewat berbeda di versi jQuery yang berbeda.Sebelum ke jQuery 1.8,
then()
sama dengandone().fail()
. Dan semua fungsi panggilan balik berbagi parameter yang sama.Tetapi pada jQuery 1.8,
then()
mengembalikan janji baru, dan jika telah mengembalikan nilai, itu akan diteruskan ke fungsi panggilan balik berikutnya.Mari kita lihat contoh berikut:
Sebelum jQuery 1.8, jawabannya harus
Semua
result
membutuhkan 3. Danthen()
fungsi selalu meneruskan objek yang ditangguhkan yang sama ke fungsi berikutnya.Tetapi pada jQuery 1.8, hasilnya harus:
Karena
then()
fungsi pertama mengembalikan janji baru, dan nilai 7 (dan ini adalah satu-satunya parameter yang akan diteruskan) diteruskan ke yang berikutnyadone()
, jadi yang keduadone()
menulisresult = 7
. Yang keduathen()
mengambil 7 sebagai nilaia
dan mengambilundefined
sebagai nilaib
, jadi yang keduathen()
mengembalikan janji baru dengan parameter NaN, dan yang terakhirdone()
mencetak NaN sebagai hasilnya.sumber
jQuery.Deferred()
dapat menerima beberapa nilai, yang diteruskan dengan benar ke nilai pertama.then()
. — Agak aneh ... karena semua yang mengikuti.then()
tidak dapat melakukannya. (Antarmuka yang dipilih melaluireturn
hanya dapat mengembalikan satu nilai.) Asli JavascriptPromise
tidak melakukan itu. (Yang lebih konsisten, jujur saja.)Ada pemetaan mental yang sangat sederhana dalam respons yang agak sulit ditemukan di jawaban lain:
done
mengimplementasikantap
seperti dalam Janji burung biruthen
mengimplementasikanthen
seperti dalam Janji ES6sumber
Hanya gunakan
.then()
Ini adalah kekurangannya
.done()
resolve()
panggilan (semua.done()
penangan akan dijalankan secara sinkron)resolve()
mungkin mendapatkan pengecualian dari.done()
penangan terdaftar (!).done()
setengah membunuh yang ditangguhkan:.done()
penangan selanjutnya akan dilewati diam-diamSaya pikir sementara itu
.then(oneArgOnly)
selalu mengharuskan.catch()
agar tidak ada pengecualian diabaikan dalam hati, tapi itu tidak benar lagi:unhandledrejection
log peristiwa tidak ditangani.then()
pengecualian di konsol (sebagai default). Sangat masuk akal! Tidak ada alasan tersisa untuk digunakan.done()
sama sekali.Bukti
Cuplikan kode berikut mengungkapkan, bahwa:
.done()
penangan akan disebut sinkron pada titikresolve()
.done()
pengaruhresolve()
resolve()
.done()
resolusi lebih lanjut.then()
tidak memiliki masalah iniunhandledrejection
tampaknya tidak ada)Btw, pengecualian dari
.done()
tidak dapat ditangkap dengan benar: karena pola sinkron.done()
, kesalahan dilemparkan pada titik.resolve()
(mungkin kode perpustakaan!) Atau pada.done()
panggilan yang melampirkan pelakunya jika ditangguhkan sudah diselesaikan.sumber
done
tidak akan dieksekusi jika yang dilakukan sebelumnya memiliki pengecualian. Tapi mengapa itu diabaikan secara diam-diam, maksud saya pengecualian terjadi jadi mengapa Anda mengatakan itu diam. 2) Saya membenciDeferred
objek karena API-nya sangat buruk. Itu terlalu rumit dan membingungkan. Kode Anda di sini juga tidak membantu membuktikan maksud Anda dan terlalu banyak kerumitan yang tidak diperlukan untuk apa yang Anda coba buktikan. 3) Mengapadone
indeks 2, 4, dan 6 dilakukan sebelum tanggal 2then
?.then()
akan dipanggil, pengecualian (pada penangan itu) dinaikkan atau tidak. Namun penambahan / sisa.done()
istirahat.Ada satu lagi perbedaan vital pada jQuery 3.0 yang dapat dengan mudah menyebabkan perilaku tak terduga dan tidak disebutkan dalam jawaban sebelumnya:
Pertimbangkan kode berikut:
ini akan menampilkan:
Sekarang, ganti
done()
denganthen()
dalam cuplikan yang sama:output sekarang:
Jadi, untuk segera ditangguhkan ditangguhkan, fungsi yang diteruskan ke
done()
akan selalu dipanggil secara sinkron, sedangkan argumen yang diteruskan kethen()
dipanggil async.Ini berbeda dari versi jQuery sebelumnya di mana kedua panggilan balik dipanggil secara serempak, sebagaimana disebutkan dalam panduan pemutakhiran :
sumber
.done()
mengakhiri rantai janji, memastikan tidak ada lagi yang bisa melampirkan langkah lebih lanjut. Ini berarti bahwa implementasi janji jQuery dapat membuang pengecualian yang tidak ditangani, karena tidak ada yang bisa menanganinya menggunakan.fail()
.Secara praktis, jika Anda tidak berencana untuk melampirkan lebih banyak langkah pada sebuah janji, Anda harus menggunakannya
.done()
. Untuk detail lebih lanjut, lihat mengapa janji harus dilakukansumber
.done()
tidak memiliki peran penghentian. Dokumentasi mengatakan, "Karena deferred.done () mengembalikan objek yang ditangguhkan, metode lain dari objek yang ditangguhkan dapat dirantai ke yang ini, termasuk metode .done () tambahan"..fail()
tidak disebutkan tetapi, ya, itu bisa dirantai juga.