Bagaimana cara saya mengembalikan respons/hasil daripada fungsi
Saya cuba mengembalikan nilai daripada panggilan balik dan memberikan hasilnya kepada pembolehubah setempat dalam fungsi dan mengembalikan pembolehubah itu, tetapi tiada satu pun daripada kaedah ini benar-benar mengembalikan respons - semuanya mengembalikan result
.
Contoh fungsi tak segerak yang menerima panggilan balik (menggunakan fungsi
function foo() { hasil var; $.ajax({ url: '...', kejayaan: fungsi (tindak balas) { hasil = respons; // membalas respons; // <- Saya juga mencubanya } }); pulangan hasil; // Ia sentiasa mengembalikan `tidak ditentukan` }
Contoh menggunakan Node.js:
function foo() { hasil var; fs.readFile("path/to/file", function(err, data) { hasil = data; // kembalikan data; // <- Saya cuba yang itu juga }); pulangan hasil; // Ia sentiasa mengembalikan `tidak ditentukan` }
Contoh
function foo() { hasil var; fetch(url).then(function(respons) { hasil = respons; // membalas respons; // <- Saya juga mencubanya }); pulangan hasil; // Ia sentiasa mengembalikan `tidak ditentukan` }
Jika andatidakmenggunakan jQuery dalam kod anda, jawapan ini adalah untuk anda
Kod anda sepatutnya kelihatan seperti ini:
Felix Kling melakukan kerja yang hebatmenulis jawapan untuk orang yang menggunakan jQuery untuk AJAX, tetapi saya memutuskan untuk menyediakan alternatif untuk orang yang tidak menggunakan jQuery.
(Nota, bagi mereka yang menggunakan
fetch
API baharu, Angular atau Promise, saya telah menambah satu lagi jawapan di bawah)Masalah yang anda hadapi
Berikut adalah ringkasan ringkas "penjelasan soalan" daripada jawapan lain, jika anda tidak pasti selepas membaca ini, sila baca jawapan itu.
AdalamAJAX bermaksudasynchronous. Ini bermakna menghantar permintaan (atau sebaliknya menerima respons) dialih keluar daripada aliran pelaksanaan biasa. Dalam contoh anda,
.send code>
立即返回,并且在调用您作为.send code>
success
回调传递的函数之前执行下一条语句return result;
kembali serta-merta dan pernyataan seterusnyareturn result;
dilaksanakan sebelum memanggil fungsi yang anda lalui sebagai panggilan baliksuccess
. kod>.Ini bermakna apabila anda kembali, pendengar yang anda tentukan belum dilaksanakan lagi, ini bermakna nilai yang anda pulangkan belum ditentukan lagi.
Berikut adalah analogi mudah:
(biola)
Disebabkan
a=5
部分尚未执行,因此返回的a
值为undefined
. AJAX berkelakuan sedemikian rupa sehingga anda memulangkan nilai sebelum pelayan mempunyai peluang untuk memberitahu pelayar anda apakah nilai itu.Satu penyelesaian yang mungkin untuk masalah ini ialahsemula aktiftulis kod yang memberitahu program anda apa yang perlu dilakukan selepas pengiraan selesai.
Ini dipanggilCPS. Pada asasnya, kami lulus
getFive
tindakan untuk dilakukan apabila selesai dan kami memberitahu kod kami cara bertindak balas apabila acara selesai (seperti panggilan AJAX kami, atau dalam kes ini, tamat masa).Penggunaan ialah:
"5" akan muncul pada skrin.(biola).
Penyelesaian yang mungkin
Pada asasnya terdapat dua cara untuk menyelesaikan masalah ini:
1. AJAX segerak - Jangan lakukannya! !
Bagi AJAX segerak,Jangan lakukannya!Jawapan Felix membuat beberapa hujah yang menarik tentang mengapa ini idea yang tidak baik. Secara keseluruhannya, ia membekukan penyemak imbas pengguna sehingga pelayan mengembalikan respons dan mencipta pengalaman pengguna yang sangat buruk. Berikut adalah satu lagi ringkasan ringkas daripada MDN yang menerangkan sebabnya:
Jika andaterpaksamelakukan ini, anda boleh melepasi bendera.Kaedah khusus adalah seperti berikut:
2. Susun semula kod
Jadikan fungsi anda menerima panggilan balik. Dalam kod contoh, anda boleh memberitahu bagaimana
foo
接受回调。我们将告诉代码当foo
bertindak balasapabilaselesai.Jadi:
menjadi:
Di sini kami menghantar fungsi tanpa nama, tetapi kami boleh menghantar rujukan kepada fungsi sedia ada dengan mudah, menjadikannya kelihatan seperti:
Untuk butiran lanjut tentang cara mencapai reka bentuk panggil balik jenis ini, lihat jawapan Felix.
Sekarang, mari kita tentukan foo sendiri untuk beroperasi dengan sewajarnya
(biola)
Kini kami mempunyai fungsifoomenerima tindakan untuk dijalankan apabila AJAX berjaya diselesaikan. Kita boleh melanjutkan fungsi ini dengan menyemak sama ada status respons bukan 200 dan mengambil tindakan yang sesuai (mewujudkan pengendali kegagalan, dsb.). Ia berkesan menyelesaikan masalah kami.
Jika anda masih menghadapi masalah memahami perkara ini,Baca AJAX untuk mendapatkan panduan untuk memulakan MDN.
Soalan
AdalamAjaxbermaksudasynchronous. Ini bermakna menghantar permintaan (atau sebaliknya menerima respons) dialih keluar daripada aliran pelaksanaan biasa. Dalam contoh anda,
$.ajax
立即返回,并且下一条语句return result;
在您作为success
panggilan balik dihantar sebelum fungsi dipanggil.Berikut adalah analogi yang diharapkan dapat menjadikan perbezaan antara strim segerak dan tak segerak lebih jelas:
Segerakkan
Bayangkan anda menghubungi rakan dan memintanya mencari maklumat untuk anda. Walaupun mungkin mengambil sedikit masa, anda menunggu melalui telefon, merenung ke angkasa, sehingga rakan anda memberikan jawapan yang anda perlukan.
Perkara yang sama berlaku apabila anda membuat panggilan fungsi yang mengandungi kod "biasa":
Walaupun sebarang kod selepas
findItem
可能需要很长时间才能执行,但var item = findItem();
mestitunggusehingga fungsi mengembalikan hasilnya.Asynchronous
Anda menghubungi rakan anda sekali lagi atas sebab yang sama. Tetapi kali ini anda memberitahunya bahawa anda cemas dan dia harus menghubungi anda semulamenggunakan telefon bimbit anda. Anda menutup telefon, meninggalkan rumah, dan melakukan apa yang anda rancangkan. Sebaik sahaja rakan anda menghubungi anda semula, anda sedang memproses maklumat yang dia berikan kepada anda.
Inilah yang berlaku apabila anda membuat permintaan Ajax.
Tidak menunggu jawapan, tetapi meneruskan pelaksanaan serta-merta dan melaksanakan pernyataan selepas panggilan Ajax. Untuk akhirnya mendapat respons, anda perlu menyediakan fungsi yang dipanggil selepas respons diterima, panggilan balik (perasan apa-apa? Panggilan balik?). Sebarang pernyataan selepas panggilan ini akan dilaksanakan sebelum panggilan balik dipanggil.
Penyelesaian
Hayati sifat tak segerak JavaScript!Walaupun sesetengah operasi tak segerak menyediakan rakan sejawatan segerak (seperti juga "Ajax"), penggunaannya secara amnya tidak digalakkan, terutamanya dalam konteks penyemak imbas.
Kenapa teruk, awak tanya?
JavaScript berjalan dalam urutan UI penyemak imbas, dan sebarang proses yang berjalan lama boleh mengunci UI, menjadikannya tidak bertindak balas. Di samping itu, terdapat had atas pada masa pelaksanaan JavaScript dan penyemak imbas akan bertanya kepada pengguna sama ada untuk meneruskan pelaksanaan.
Semua ini membawa kepada pengalaman pengguna yang sangat teruk. Pengguna tidak akan dapat mengetahui sama ada semuanya berfungsi dengan betul. Di samping itu, kesannya akan menjadi lebih teruk bagi pengguna dengan kelajuan Internet yang lebih perlahan.
Di bawah ini kami membentangkan tiga penyelesaian berbeza yang semuanya membina antara satu sama lain:
async/await
(ES2017+, berfungsi dalam pelayar lama jika anda menggunakan transpiler atau penjana semula)then() 的 Promise
(ES2015+, berfungsi dalam penyemak imbas lama jika anda menggunakan salah satu daripada banyak perpustakaan Promise)Tiga ciri ini tersedia dalam penyemak imbas semasa dan Node 7+.
ES2017+: Gunakan
async/await 进行承诺
Keluaran ECMAScript 2017 memperkenalkansokongan peringkat sintaksuntuk fungsi tak segerak. Dengan
async
和await
anda boleh menulis secara tak segerak dalam "gaya segerak". Kod tersebut masih tidak segerak, tetapi lebih mudah dibaca/difahami.
async sentiasa mengembalikan Janji.async/await
构建在 Promise 之上:async
函数始终返回 Promise。await
Dibina atas Janji: Fungsitunggu "membuka" Janji dan sama ada menghasilkan nilai yang Janji selesaikan, atau melemparkan ralat jika Janji ditolak.
: Anda hanya boleh menggunakanasync
函数或JavaScript 模块。模块外部不支持顶级await
,因此您可能必须创建异步 IIFE (立即调用函数表达式)来启动异步
PENTINGtunggu dalam fungsiasync ataumodul JavaScript
async. Peringkat teratas tunggu
tidak disokong di luar modul, jadi anda mungkin perlu mencipta IIFE tak segerak (Segera menggunakan ungkapan fungsi) untuk memulakan konteksasync (jika tidak menggunakan modul).Anda boleh membaca tentang
dan
findItem()
menunggu.Berikut ialah contoh yang memperincikan fungsitertunda
Versi pelayardan nodasync/await
findItem() di atas:semasa menyokong
. Anda juga boleh menukar kod anda kepada ES5 dengan bantuan regenerator
(atau alatan yang menggunakan regenerator) untuk menyokong persekitaran yang lebih lama sepertiBabel
). Biarkan fungsi menerima panggilan balik Panggil balik ialah apabila fungsi 1 dihantar ke fungsi 2. Fungsi 2 boleh memanggil fungsi 1 apabila ia sudah siap. Dalam konteks proses tak segerak, panggilan balik dipanggil apabila proses tak segerak selesai. Biasanya, keputusan dihantar ke panggilan balik.Dalam contoh soalan, anda boleh membuat
foo
接受回调并将其用作success
panggilan balik. Jadi inimenjadi
Di sini kami mentakrifkan fungsi "sebaris", tetapi anda boleh lulus mana-mana rujukan fungsi:
foo
itu sendiri ditakrifkan seperti berikut:callback
将引用我们调用时传递给foo
的函数,并将其传递给success
。 IE。一旦Ajax请求成功,$.ajax
将调用callback
并将响应传递给回调(可以用result
apabila kami memanggilnya dan menghantarnya kepada$.ajax
akan memanggilcallback
dan menghantar respons kepada panggilan balik (yang boleh dirujuk denganresult
, sejak begitulah cara kita mentakrifkan panggilan balik The way).Anda juga boleh memproses respons sebelum menghantarnya ke panggilan balik:
Menulis kod menggunakan panggilan balik adalah lebih mudah daripada yang kelihatan. Lagipun, JavaScript dalam penyemak imbas sebahagian besarnya didorong oleh peristiwa (peristiwa DOM). Menerima respons Ajax tidak lebih daripada peristiwa. Kesukaran mungkin timbul apabila anda perlu menggunakan kod pihak ketiga, tetapi kebanyakan masalah boleh diselesaikan dengan hanya memikirkan tentang aliran aplikasi.
ES2015+: denganthen()的 Promise >
Promise APIialah ciri ECMAScript 6 (ES2015) baharu, tetapi ia sudah mempunyaisokongan penyemak imbasyang baik. Terdapat juga banyak perpustakaan yang melaksanakan API Promises standard dan menyediakan kaedah tambahan untuk memudahkan penggunaan dan komposisi fungsi tak segerak (cth.,Bluebird).
Janji adalah wadah nilaimasa depan. Apabila Janji menerima nilai (diselesaikan) atau dibatalkan (ditolak), ia memberitahu mana-mana "pendengar" yang ingin mengakses nilai tersebut.
Kelebihan daripada panggilan balik biasa ialah ia membolehkan anda memisahkan kod anda dan lebih mudah untuk ditulis.
Ini adalah contoh penggunaan Promise: