Bagaimana cara mengembalikan respon dari panggilan asynchronous?
Aku punya fungsi foo
yang membuat permintaan Ajax. Bagaimana saya bisa mengembalikan respon dari foo
?
Aku mencoba kembali nilai dari keberhasilan
callback serta memberikan respon terhadap variabel lokal dalam fungsi dan kembali yang satu itu, tapi tak satu pun dari cara-cara itu benar-benar kembali respon.
function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
result = response;
// return response; // <- I tried that one as well
}
});
return result;
}
var result = foo(); // It always ends up being `undefined`.
5183
36
Meskipun
findItem
mungkin memakan waktu lama untuk mengeksekusi, kode apapun yang datang setelahvar item = findItem();
memiliki ke menunggu sampai fungsi ini mengembalikan hasil.Asynchronous
Anda menelepon teman anda lagi untuk alasan yang sama. Tapi kali ini anda katakan padanya bahwa anda sedang terburu-buru dan dia harus menelepon anda kembali di ponsel anda. Anda menutup, meninggalkan rumah dan melakukan apa pun yang anda berencana untuk melakukan. Setelah teman anda memanggil anda kembali, anda berurusan dengan informasi yang dia berikan kepada anda. Yang's apa yang's terjadi ketika anda melakukan permintaan Ajax.
Alih-alih menunggu respon, eksekusi berlanjut segera dan pernyataan setelah Ajax call dijalankan. Untuk mendapatkan respon akhirnya, anda menyediakan fungsi yang akan dipanggil setelah respon diterima, a panggil ulang (melihat sesuatu? panggil kembali ?). Setiap pernyataan yang datang setelah panggilan yang dieksekusi sebelum balik disebut.
Solusi(s)
Merangkul asynchronous alam JavaScript! Sedangkan tertentu operasi asynchronous memberikan sinkron rekan-rekan (jadi tidak "Ajax"), it's umumnya tidak dianjurkan untuk menggunakannya, terutama di browser konteks. Mengapa kau bertanya? JavaScript berjalan di UI thread browser dan panjang proses yang berjalan akan mengunci UI, sehingga tidak responsif. Selain itu, ada batas atas pada waktu eksekusi untuk JavaScript dan browser akan meminta pengguna apakah akan melanjutkan eksekusi atau tidak. Semua ini benar-benar buruk untuk pengguna. Pengguna tidak't dapat memberitahu apakah semuanya bekerja dengan baik atau tidak. Selain itu, efeknya akan lebih buruk untuk pengguna dengan koneksi yang lambat. Dalam berikut kita akan melihat tiga solusi yang berbeda yang semua bangunan di atas satu sama lain:
async/menanti
(ES2017+, tersedia di browser lama jika anda menggunakan transpiler atau regenerator)Dengan janji-janji
maka()
(ES2015+, tersedia di browser lama jika anda menggunakan salah satu dari banyak janji perpustakaan) Semua tiga tersedia dalam browser yang ada saat ini, dan node 7+.ES2017+: dengan janji-Janji
async/menanti
ECMAScript versi dirilis pada 2017 diperkenalkan sintaks-tingkat dukungan untuk fungsi asynchronous. Dengan bantuan
async
danmenunggu
, anda dapat menulis asynchronous dalam "sinkron gaya". Kode ini masih asynchronous, tapi itu's mudah untuk membaca/memahami.async/menanti
dibangun di atas janji-janji: sebuahasync
fungsi selalu kembali janji.menunggu
"sesuatu" janji dan baik mengakibatkan nilai janji itu diselesaikan dengan atau melempar kesalahan jika janji itu ditolak. Penting: Anda hanya dapat menggunakanmenginap
di dalamasync
fungsi. Sekarang, tingkat atasmenunggu
isn't belum didukung, sehingga anda mungkin harus membuat async HIDUP (Segera Dipanggil Fungsi Ekspresi) untuk memulai sebuahasync
konteks. Anda dapat membaca lebih lanjut tentangasync
danmenunggu
pada MDN. Berikut adalah contoh yang dibangun di atas keterlambatan atas:Saat ini browser dan node versi dukungan
async/menanti
. Anda juga dapat mendukung lebih tua lingkungan dengan mengubah kode anda untuk ES5 dengan bantuan regenerator (atau alat-alat yang menggunakan regenerator, seperti Babel).Mari fungsi menerima callback
Callback adalah hanya fungsi yang dilewatkan ke fungsi lain. Lainnya fungsi dapat memanggil fungsi berlalu kapan pun siap. Dalam konteks proses asynchronous, callback yang akan dipanggil setiap kali asynchronous proses ini dilakukan. Biasanya, hasilnya akan diteruskan ke callback. Dalam contoh dari pertanyaan, anda dapat membuat
foo
menerima panggilan balik dan menggunakannya sebagaikeberhasilan
callback. Jadi, inimenjadi
Di sini kita mendefinisikan fungsi "inline" tapi anda dapat melewati setiap fungsi referensi:
foo
itu sendiri didefinisikan sebagai berikut:balik
akan mengacu pada fungsi kita lulus untukfoo
ketika kita panggil dan kita hanya lulus padakeberhasilan
. I. e. setelah permintaan Ajax berhasil,$.ajax
akan memanggilbalik
dan lulus menanggapi panggilan balik (yang dapat disebut denganhasil
, karena ini adalah bagaimana kita mendefinisikan callback). Anda juga dapat memproses respon sebelum diteruskan ke callback:It's mudah untuk menulis kode menggunakan callback dari itu mungkin tampak. Setelah semua, JavaScript dalam browser ini sangat-event (peristiwa DOM). Menerima Ajax respon tidak lain adalah sebuah event. Kesulitan bisa timbul ketika anda harus bekerja dengan kode pihak ketiga, tetapi sebagian besar masalah dapat diselesaikan dengan hanya berpikir melalui alur aplikasi.
ES2015+: janji-Janji dengan maka()
The Janji API adalah sebuah fitur baru dari ECMAScript 6 (ES2015), tetapi memiliki baik dukungan browser sudah. Ada juga banyak perpustakaan yang menerapkan standar Menjanjikan API dan memberikan tambahan metode untuk kemudahan penggunaan dan komposisi asynchronous fungsi (misalnya bluebird). Janji adalah wadah untuk masa depan nilai-nilai. Ketika janji menerima nilai (itu menyelesaikan) atau ketika itu dibatalkan (ditolak), itu akan memberitahu semua "pendengar" yang ingin mengakses nilai ini. Keuntungan atas polos callback adalah bahwa mereka memungkinkan anda untuk memisahkan kode anda dan mereka lebih mudah untuk menulis. Berikut ini adalah contoh sederhana menggunakan berjanji:
Diterapkan untuk kami Ajax call kita bisa menggunakan janji-janji seperti ini:
Menggambarkan semua keuntungan yang menjanjikan tawarkan adalah di luar lingkup dari jawaban ini, tapi jika anda menulis kode baru, anda harus secara serius mempertimbangkan mereka. Mereka memberikan abstraksi dan pemisahan dari kode anda. Informasi lebih lanjut tentang janji-janji: HTML5 batu - JavaScript janji-Janji
Catatan: jQuery's tangguhan benda
Tangguhan benda ini adalah jQuery's custom pelaksanaan janji-janji (sebelum Janji API adalah standar). Mereka berperilaku hampir seperti janji-janji tapi mengekspos sedikit berbeda API. Setiap metode Ajax jQuery sudah kembali "tangguhan objek" (sebenarnya janji tangguhan objek) yang dapat anda baru saja kembali dari fungsi:
Catatan: Janji gotchas
Perlu diingat bahwa janji-janji dan tangguhan benda-benda yang hanya wadah untuk nilai masa depan, mereka bukan nilai itu sendiri. Untuk contoh, misalkan anda memiliki yang berikut ini:
Ini salah memahami kode di atas asynchrony masalah. Secara khusus,
$.ajax()
doesn't membekukan kode sementara itu cek '/password' halaman pada server anda - ia akan mengirimkan permintaan ke server dan sementara menunggu, segera kembali jQuery Ajax Tangguhan objek, bukan respon dari server. Yang berartijika
pernyataan akan selalu mendapatkan ini Ditangguhkan objek, memperlakukannya sebagaibenar
, dan melanjutkan seolah-olah user tersebut login. Tidak baik. Tapi perbaiki mudah:Tidak dianjurkan: Sinkron "Ajax" panggilan
Seperti yang saya sebutkan, beberapa(!) operasi asynchronous telah sinkron rekan-rekan. Saya don't advokat yang mereka gunakan, tapi untuk kelengkapan' demi, di sini adalah bagaimana anda akan melakukan panggilan sinkron:
Tanpa jQuery
Jika anda langsung menggunakan
XMLHTTPRequest
objek, luluspalsu
sebagai argumen ketiga untuk.open
.jQuery
Jika anda menggunakan jQuery, anda dapat mengatur
async
pilihan untukpalsu
. Perhatikan bahwa opsi ini adalah tidak berlaku lagi sejak jQuery 1.8. Anda kemudian dapat baik yang masih menggunakansukses
callback atau mengaksesresponseText
milik jqXHR objek:Jika anda menggunakan jQuery Ajax metode, seperti
$.dapatkan
,$.getJSON
, dll., anda harus mengubahnya ke$.ajax
(karena anda hanya dapat melewatkan parameter konfigurasi untuk$.ajax
). Kepala-up! Hal ini tidak mungkin untuk membuat sebuah sinkron JSONP permintaan. JSONP dengan sifatnya yang selalu asynchronous (satu lagi alasan untuk tidak bahkan mempertimbangkan opsi ini).Jika anda're not menggunakan jQuery dalam kode anda, jawaban ini adalah untuk anda
Kode anda harus menjadi sesuatu di sepanjang baris ini:
Felix Kling melakukan pekerjaan baik menulis jawaban untuk orang-orang yang menggunakan jQuery untuk AJAX, I've memutuskan untuk memberikan alternatif bagi orang-orang yang tidak't.
(Catatan, bagi mereka yang menggunakan baru
mengambil
API, Sudut atau janji-janji yang saya've menambahkan jawaban lain di bawah ini)Apa yang anda're menghadapi
Ini adalah ringkasan singkat dari "Penjelasan masalah" dari yang lain menjawab, jika anda'kembali tidak pasti setelah baca ini, baca itu.
Yang ** di AJAX merupakan singkatan dari asynchronous**. Itu berarti mengirimkan permintaan (atau lebih tepatnya menerima respon) diambil dari alur eksekusi normal. Dalam contoh anda,
.kirim
kembali segera dan pernyataan berikutnya,return hasil;
, dieksekusi sebelum fungsi anda lulus sebagaikeberhasilan
callback itu bahkan disebut.Ini berarti ketika anda're kembali, pendengar anda'telah ditentukan tidak melaksanakan lagi, yang berarti nilai anda're kembali belum didefinisikan.
Berikut ini adalah analogi sederhana
[(Biola)][2]
Nilai dari
a
kembaliundefined
sejaka=5
bagian tidak dieksekusi lagi. AJAX bertindak seperti ini, anda're kembali ke nilai sebelum server punya kesempatan untuk memberitahu browser anda apa itu nilai lebih.Salah satu solusi yang mungkin untuk masalah ini adalah untuk kode re-actively , mengatakan program anda apa yang harus dilakukan ketika perhitungan selesai.
Ini disebut CPS. Pada dasarnya, kita're lewat
getFive
tindakan untuk melakukan ketika itu selesai, kami're memberitahu kode kita bagaimana harus bereaksi ketika acara selesai (seperti AJAX call, atau dalam hal ini timeout).Penggunaan akan sama:
Yang harus waspada "5" untuk layar. [(Biola)][4].
Solusi yang mungkin
Pada dasarnya ada dua cara bagaimana untuk memecahkan masalah ini:
1. Sinkron AJAX - Don't melakukan itu!!
Adapun sinkron AJAX, don't melakukan itu! Felix's jawaban menimbulkan beberapa argumen menarik tentang mengapa hal itu's merupakan ide yang buruk. Untuk jumlah itu, it'll membekukan pengguna's browser hingga server kembali respon dan membuat sangat buruk untuk pengguna. Berikut ini adalah ringkasan singkat yang diambil dari MDN mengapa:
Jika anda have untuk melakukan ini, anda dapat melewati bendera: di Sini adalah bagaimana:
2. Merestrukturisasi kode
Mari fungsi anda menerima panggilan balik. Dalam contoh kode
foo
dapat dibuat untuk menerima panggilan balik. Kami'akan menceritakan kepada kami kode cara react ketikafoo
selesai.Jadi:
Menjadi:
Di sini kami melewati fungsi anonim, tapi kita bisa dengan mudah melewati sebuah referensi yang ada fungsi, sehingga terlihat seperti:
Untuk rincian lebih lanjut tentang cara semacam ini callback desain selesai, periksa Felix's jawaban.
Sekarang, let's menentukan foo sendiri untuk bertindak sesuai
[(biola)][6]
Sekarang kita telah membuat kami foo fungsi menerima tindakan untuk menjalankan ketika AJAX selesai dengan sukses, kita dapat memperpanjang ini lebih lanjut dengan memeriksa jika respon status tidak 200 dan bertindak sesuai dengan itu (membuat gagal handler dan semacamnya). Dapat secara efektif memecahkan masalah kami.
Jika anda're masih memiliki waktu yang sulit memahami ini baca AJAX panduan memulai di MDN.
XMLHttpRequest 2 (pertama-tama membaca jawaban dari Benjamin Gruenbaum & Felix Kling) Jika anda don't menggunakan jQuery dan ingin pendek yang bagus XMLHttpRequest 2 yang bekerja pada browser modern dan juga di mobile browser, saya sarankan untuk menggunakan cara ini:
Seperti yang anda lihat:
Atau jika untuk beberapa alasan anda
bind()
callback untuk kelas:Contoh:
Atau (di atas satu lebih baik fungsi anonim yang selalu menjadi masalah):
Ada yang lebih mudah. Sekarang beberapa orang mungkin akan mengatakan bahwa itu's baik untuk menggunakan onreadystatechange atau bahkan XMLHttpRequest nama variabel. Yang's salah. Check out XMLHttpRequest fitur-fitur canggih Hal itu didukung semua *browser modern. Dan saya bisa mengkonfirmasi karena saya'm menggunakan pendekatan ini karena XMLHttpRequest 2 ada. Aku tidak pernah punya jenis masalah pada semua browser yang saya gunakan. onreadystatechange ini hanya berguna jika anda ingin mendapatkan header pada negara 2. Menggunakan
XMLHttpRequest
nama variabel lain adalah kesalahan besar yang anda butuhkan untuk menjalankan callback dalam onload/oreadystatechange penutupan yang lain anda kehilangan itu.Sekarang jika anda ingin sesuatu yang lebih kompleks menggunakan pos dan FormData anda dapat dengan mudah memperluas fungsi ini:
Sekali lagi ... itu's yang sangat singkat fungsi, tetapi tidak mendapatkan & posting. Contoh penggunaan:
Atau lulus penuh elemen form (
document.getElementsByTagName('bentuk')[0]
):Atau mengatur beberapa nilai-nilai adat:
Seperti yang anda lihat saya didn't melaksanakan sinkronisasi... itu's hal yang buruk. Setelah mengatakan bahwa ... mengapa don't melakukannya dengan cara yang mudah?
Seperti yang disebutkan dalam komentar penggunaan kesalahan && sinkron tidak benar-benar istirahat titik jawabannya. Yang bagus cara singkat untuk menggunakan Ajax dalam cara yang tepat? Error handler
Dalam script di atas, anda memiliki error handler yang statis didefinisikan sehingga tidak membahayakan fungsi. Error handler dapat digunakan untuk fungsi-fungsi lain juga. Tapi untuk benar-benar keluar kesalahan hanya cara adalah dengan menulis URL yang salah dalam hal ini setiap browser melempar kesalahan. Penangan kesalahan yang mungkin berguna jika anda mengatur header kustom, mengatur responseType untuk blob array buffer atau apapun... Bahkan jika anda lulus 'POSTAPAPAP' sebagai metode itu tidak't melempar kesalahan. Bahkan jika anda lulus 'fdggdgilfdghfldj' sebagai formdata itu tidak't melempar kesalahan. Dalam kasus pertama kesalahan dalam
displayAjax()
bawahini.statusText
sebagaiMetode tidak Diizinkan
. Dalam kedua kasus, itu hanya bekerja. Anda harus memeriksa pada sisi server jika anda melewati tiang kanan data. cross-domain tidak diperbolehkan melempar kesalahan secara otomatis. Dalam respon kesalahan, tidak ada kesalahan kode. Hanya adaini.ketik
yang diatur untuk kesalahan. Mengapa menambahkan error handler jika anda benar-benar tidak memiliki kontrol atas kesalahan? Sebagian besar kesalahan kembali dalam hal ini fungsi callbackdisplayAjax()
. Jadi: Tidak perlu untuk pengecekan kesalahan jika anda're dapat copy dan paste URL dengan benar. ;) PS: Sebagai tes pertama saya menulis x('x', displayAjax)..., dan itu benar-benar mendapat respon...??? Jadi aku memeriksa folder mana HTML-terletak, dan ada sebuah file yang bernama 'x.xml'. Jadi bahkan jika anda lupa ekstensi file anda XMLHttpRequest 2 AKAN menemukannya. Saya LOL'dBaca file sinkron Don't melakukan itu. Jika anda ingin memblokir browser untuk sementara beban besar yang bagus
.txt
file sinkron.Sekarang anda dapat melakukan
Tidak ada cara lain untuk melakukan ini di non-asynchronous cara. (Ya, dengan setTimeout loop... tapi serius?) Titik lain adalah... jika anda bekerja dengan Api atau hanya daftar anda sendiri's file atau apapun yang anda selalu menggunakan fungsi yang berbeda untuk setiap permintaan... Hanya jika anda memiliki sebuah halaman di mana anda memuat selalu sama XML/JSON atau apa pun yang anda butuhkan hanya satu fungsi. Dalam kasus itu, memodifikasi sedikit Ajax fungsi dan mengganti b dengan fungsi khusus.
Fungsi di atas adalah untuk penggunaan dasar. Jika anda ingin MEMPERPANJANG fungsi... Ya, anda bisa. I'm menggunakan banyak Api dan salah satu fungsi yang saya mengintegrasikan ke setiap halaman HTML adalah pertama fungsi Ajax di jawaban ini, dengan hanya MENDAPATKAN... Tetapi anda dapat melakukan banyak hal dengan XMLHttpRequest 2: Saya membuat sebuah download manager (menggunakan berkisar di kedua sisi dengan resume, filereader, filesystem), berbagai resizers gambar konverter menggunakan kanvas, mengisi web SQL database dengan base64images dan banyak lagi... Tapi dalam kasus ini anda harus membuat sebuah fungsi hanya untuk tujuan itu... kadang-kadang anda perlu gumpalan, array buffer, anda dapat mengatur header, mengganti tipe mime dan ada lebih banyak... Tapi pertanyaannya di sini adalah bagaimana untuk kembali ke Ajax respon... (saya menambahkan cara yang mudah.)
Jika anda're menggunakan janji-janji, ini jawabannya untuk anda.
Ini berarti AngularJS, jQuery (ditangguhkan), XHR asli's penggantian (fetch), EmberJS, BackboneJS's menyimpan atau setiap node perpustakaan yang kembali janji-janji. Kode anda harus menjadi sesuatu di sepanjang baris ini:
Felix Kling melakukan pekerjaan baik menulis jawaban untuk orang-orang yang menggunakan jQuery dengan callback untuk AJAX. Aku punya jawaban untuk XHR asli. Jawaban ini adalah untuk penggunaan generik dari janji-janji baik di frontend atau backend.
Masalah inti
JavaScript concurrency model di browser dan server dengan NodeJS/io.js adalah asynchronous dan reactive. Setiap kali anda memanggil sebuah metode yang mengembalikan sebuah janji,
kemudian
penangan always dieksekusi asynchronously - yang, setelah kode di bawah mereka yang tidak dalam.kemudian
handler. Ini berarti ketika anda're kembalidata
kemudian
handler anda've didefinisikan tidak mengeksekusi belum. Hal ini pada gilirannya berarti bahwa nilai anda're kembali belum diatur ke nilai yang benar pada waktunya. Berikut ini adalah analogi sederhana untuk masalah ini:Nilai dari
data
adalahundefined
sejakdata = 5
bagian tidak dieksekusi lagi. Kemungkinan akan mengeksekusi di kedua tetapi pada saat itu adalah tidak relevan dengan nilai yang dikembalikan. Sejak operasi belum terjadi (AJAX, server call, IO, timer) anda're kembali ke nilai sebelum permohonan punya kesempatan untuk memberitahu anda kode apa itu nilai lebih. Salah satu solusi yang mungkin untuk masalah ini adalah untuk kode re-actively , mengatakan program anda apa yang harus dilakukan ketika perhitungan selesai. Janji-janji aktif mengaktifkan ini dengan menjadi temporal (waktu-sensitif) di alam.Rekap cepat pada janji-janji
Janji adalah value atas time. Janji negara, mereka mulai sebagai pending dengan tidak ada nilai dan dapat menetap untuk:
kemudian
penangan untuk janji-janji untuk mengekstrak nilai mereka dan menangani kesalahan.kemudian
penangan memungkinkan chaining dari panggilan. Janji-janji yang dibuat oleh menggunakan Api yang kembali them. Misalnya, lebih modern AJAX penggantiambil
atau jQuery's$.dapatkan
kembali janji-janji. Ketika kita menyebut.kemudian
pada janji dan return sesuatu dari hal itu - kita mendapatkan janji untuk the diproses value. Jika kita kembali lagi janji kita'll mendapatkan hal-hal yang menakjubkan, tapi let's menahan kuda-kuda kami.Dengan janji-janji
Let's melihat bagaimana kita dapat memecahkan masalah di atas dengan janji-janji. Pertama, let's menunjukkan pemahaman kita tentang janji serikat dari atas dengan menggunakan Janji constructor untuk menciptakan fungsi delay:
Sekarang, setelah kita dikonversi setTimeout untuk menggunakan janji-janji, kita dapat menggunakan
kemudian
untuk membuat hitungan:Pada dasarnya, bukannya kembali value yang kita dapat't lakukan karena concurrency model - kita're kembali wrapper untuk nilai yang kita dapat unwrap dengan
kemudian
. It's seperti sebuah kotak yang dapat anda buka dengankemudian
.Menerapkan ini
Ini adalah singkatan yang sama untuk anda asli API panggilan, anda dapat:
Jadi ini bekerja sama dengan baik. Kami've belajar kita bisa't kembali nilai-nilai dari yang sudah panggilan asynchronous tapi kita bisa menggunakan janji-janji dan rantai mereka untuk melakukan pengolahan. Sekarang kita tahu bagaimana untuk mengembalikan respon dari panggilan asynchronous.
ES2015 (ES6)
ES6 memperkenalkan generator yang adalah fungsi yang dapat kembali di tengah dan kemudian melanjutkan point mereka di. Ini biasanya berguna untuk urutan, misalnya:
Adalah fungsi yang mengembalikan sebuah iterator urutan
1,2,3,3,3,3,....
yang dapat diiterasi. Sementara ini menarik sendiri dan membuka ruang untuk banyak kemungkinan ada salah satu kasus yang menarik. Jika urutan kita're memproduksi adalah suatu urutan dari tindakan-tindakan dan bukan angka-angka - kita bisa pause berfungsi setiap kali tindakan menyerah dan menunggu untuk itu sebelum kita melanjutkan fungsi. Jadi bukan urutan dari angka-angka, kita perlu urutan future nilai - nilai itu adalah: janji-janji. Ini agak rumit tapi sangat kuat trik yang memungkinkan kita menulis kode asinkron di sinkron dengan cara. Ada beberapa "pelari" yang melakukan ini untuk anda, menulis satu lebih pendek beberapa baris kode, tetapi adalah di luar lingkup dari jawaban ini. I'akan menggunakan Bluebird'sJanji.coroutine
di sini, tapi ada pembungkus lain sepertico
atauQ. async
.Metode ini kembali janji itu sendiri, yang dapat kita konsumsi dari yang lain coroutines. Misalnya:
ES2016 (ES7)
Di ES7, hal ini lebih standar, ada beberapa proposal yang sekarang, tapi pada semua dari mereka, anda bisa
menunggu
janji. Ini adalah hanya "gula" (lebih bagus sintaks) untuk ES6 proposal di atas dengan menambahkanasync
danmenunggu
kata kunci. Membuat contoh di atas:Itu masih kembali janji sama saja :)
Anda menggunakan Ajax dengan benar. Idenya adalah untuk tidak memilikinya kembali apa-apa, tapi malah menyerahkan data ke sesuatu yang disebut fungsi callback, yang menangani data.
Yaitu:
Kembali apa-apa di kirim handler tidak akan melakukan apa-apa. Sebagai gantinya, anda harus tangan baik dari data, atau melakukan apa yang anda inginkan dengan itu secara langsung dalam keberhasilan fungsi.
Solusi yang paling sederhana adalah membuat sebuah fungsi JavaScript dan panggilan untuk Ajax
sukses
callback.Saya akan menjawab dengan mengerikan yang tampak, digambar tangan komik. Gambar kedua adalah alasan mengapa
hasil
adalahundefined
di kode anda contoh.Angular1
Untuk orang-orang yang menggunakan AngularJS, dapat menangani situasi ini dengan menggunakan
janji-Janji
.Di sini ia berkata,
Anda dapat menemukan baik penjelasan di sini juga.
Contoh yang ditemukan dalam docs disebutkan di bawah ini.
Angular2 dan Kemudian
Di
Angular2
dengan melihat contoh berikut ini, tapi recommended untuk menggunakanDiamati
denganAngular2
.}
Anda dapat mengkonsumsi dengan cara ini,
Lihat original posting di sini. Tapi Ketangkasan tidak mendukung asli es6 janji-Janji, jika anda ingin menggunakannya, anda mungkin perlu plugin untuk itu.
Selain itu di sini adalah janji-janji spec mendefinisikan sini.
Sebagian besar jawaban di sini memberikan saran-saran yang berguna untuk ketika anda memiliki satu operasi asinkron, tapi kadang-kadang, ini muncul ketika anda perlu untuk melakukan operasi asinkron untuk setiap masuk dalam array atau list-seperti struktur. Godaan untuk melakukan hal ini:
Contoh:
Alasan yang doesn't bekerja adalah bahwa callback dari
doSomethingAsync
belum't berjalan namun dengan waktu anda're mencoba untuk menggunakan hasil. Jadi, jika anda memiliki sebuah array (atau daftar dari beberapa jenis) dan ingin melakukan operasi async untuk setiap entri, anda memiliki dua pilihan: Melakukan operasi secara paralel (tumpang tindih), atau seri (satu demi satu dalam urutan).Paralel
Anda dapat memulai semua dari mereka dan menjaga melacak dari berapa banyak callback anda're mengharapkan, dan kemudian menggunakan hasil ketika anda've mendapat banyak callback:
Contoh:
(Kita bisa melakukan jauh dengan
mengharapkan
dan hanya menggunakanhasil.panjang === ukuranarray.panjang
, tapi yang membuat kita terbuka untuk kemungkinan bahwaukuranarray
berubah sementara panggilan yang luar biasa...) Perhatikan bagaimana kita menggunakanindex
dariforEach
untuk menyimpan hasilnya dihasil
di posisi yang sama sebagai entri ini berkaitan dengan, bahkan jika hasil tiba out of order (sejak async panggilan don't harus lengkap dalam urutan di mana mereka mulai). Tapi bagaimana jika anda perlu untuk kembali hasil-hasil dari sebuah fungsi? Sebagai jawaban lain telah menunjukkan, anda dapat't; anda harus memiliki fungsi menerima dan menelepon balik (atau kembali Janji). Berikut ini's callback versi:Contoh:
Atau di sini's versi kembali
Janji
sebagai gantinya:Tentu saja, jika
doSomethingAsync
melewati kami kesalahan-kesalahan, kita'd gunakanmenolak
untuk menolak janji ketika kita punya kesalahan.) Contoh:(Atau secara bergantian, anda bisa membuat wrapper untuk
doSomethingAsync
yang kembali berjanji, dan kemudian lakukan hal di bawah ini...) JikadoSomethingAsync
memberi anda Janji, anda dapat menggunakanJanji.semua
:Jika anda tahu bahwa
doSomethingAsync
akan mengabaikan kedua dan ketiga argumen, anda hanya dapat melewati langsung kepeta
(peta
panggilan balik dengan tiga argumen, tapi kebanyakan orang hanya menggunakan sebagian besar waktu):Contoh:
Perhatikan bahwa
Janji.semua
menyelesaikan janjinya dengan array hasil dari semua janji-janji yang anda berikan ketika mereka semua diselesaikan, atau menolak janjinya ketika pertama dari janji-janji yang kau berikan itu menolak.Seri
Misalkan anda don't ingin operasi yang harus di paralel? Jika anda ingin menjalankan mereka satu demi satu, anda harus menunggu untuk setiap operasi untuk menyelesaikan sebelum anda memulai berikutnya. Berikut ini's contoh dari fungsi yang melakukan itu dan panggilan panggilan balik dengan hasil:
(Karena kita're melakukan pekerjaan dalam seri ini, kita hanya dapat menggunakan
hasil.push(hasil)
karena kita tahu kita tidak't mendapatkan hasil yang keluar dari urutan. Di atas kita bisa menggunakanhasil[index] = hasil;
, namun dalam beberapa contoh berikut kita don't memiliki indeks untuk digunakan.) Contoh:(Atau, sekali lagi, membangun sebuah wrapper untuk
doSomethingAsync
yang memberikan janji dan melakukan di bawah ini...) JikadoSomethingAsync
memberikan anda sebuah Janji, jika anda dapat menggunakan ES2017+ sintaks (mungkin dengan transpiler seperti Babel), anda dapat menggunakanasync
fungsi denganbagi-dari
danmenunggu
:Contoh:
Jika anda dapat't menggunakan ES2017+ sintaks (belum), anda dapat menggunakan variasi pada "Janji mengurangi" pola (ini lebih kompleks dari yang biasa Berjanji mengurangi karena kami're tidak melewati hasil dari yang satu ke yang berikutnya, tapi bukannya mengumpulkan hasil mereka dalam array):
Contoh:
...yang kurang rumit dengan ES2015+ panah fungsi:
Contoh:
Lihat contoh ini:
Seperti yang anda lihat
getJoke
adalah kembali diselesaikan janji (diselesaikan ketika kembalires.data.nilai
). Jadi anda menunggu sampai $http.dapatkan permintaan selesai dan kemudian console.log(res.joke) dieksekusi (seperti normal asynchronous flow).Ini adalah plnkr:
http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/
ES6 cara (async - menanti)
Ini adalah salah satu tempat yang dua cara mengikat data atau toko konsep yang's digunakan dalam kerangka kerja JavaScript akan bekerja besar untuk anda...
Jadi jika anda menggunakan Sudut, Bereaksi atau framework lain yang melakukan dua cara mengikat data atau toko konsep masalah ini hanya tetap untuk anda, sehingga mudah di word, anda hasilnya adalah
undefined
di tahap pertama, maka anda sudah mendapathasil = tidak terdefinisi
sebelum anda menerima data, kemudian segera setelah anda mendapatkan hasil, itu akan diperbarui dan bisa ditugaskan untuk nilai baru yang respon dari Ajax call...Tapi bagaimana anda bisa melakukan itu di murni javascript atau jQuery misalnya anda bertanya pertanyaan ini?
Anda dapat menggunakan panggil ulang, janji baru diamati untuk menangani hal ini untuk anda, misalnya dalam janji-janji kita memiliki beberapa fungsi seperti
sukses()
ataumaka()
yang akan dieksekusi ketika data anda siap untuk anda, yang sama dengan callback atau berlangganan fungsi diamati.Misalnya dalam kasus anda yang anda gunakan jQuery, anda dapat melakukan sesuatu seperti ini:
Untuk informasi lebih lanjut belajar tentang janji dan diamati yang cara-cara baru untuk melakukan hal ini async barang.
Pendekatan lain untuk mengembalikan sebuah nilai dari sebuah fungsi asynchronous, adalah untuk lulus dalam suatu objek yang akan menyimpan hasil dari asynchronous fungsi.
Berikut adalah contoh yang sama:
Saya menggunakan
hasil
objek untuk menyimpan nilai selama operasi asynchronous. Hal ini memungkinkan hasilnya akan tersedia bahkan setelah asynchronous pekerjaan.Saya menggunakan pendekatan ini banyak. Aku akan tertarik untuk mengetahui bagaimana pendekatan ini bekerja di mana kabel hasilnya kembali melalui berturut-turut modul yang terlibat.
Sementara janji-janji dan callback bekerja dengan baik dalam banyak situasi, itu adalah rasa sakit di bagian belakang untuk mengekspresikan sesuatu seperti:
Anda'd akhirnya akan melalui
async1
; memeriksa apakahnama
undefined atau tidak dan menelepon balik yang sesuai.Sementara itu okay kecil contoh-contoh itu akan menjengkelkan ketika anda memiliki banyak kasus-kasus serupa dan penanganan kesalahan yang terlibat.
Serat
membantu dalam memecahkan masalah.Anda dapat checkout proyek di sini.
Jawaban singkatnya adalah, anda harus mengimplementasikan callback seperti ini:
Berikut contoh yang saya tulis menunjukkan bagaimana untuk
Ini contoh kerja adalah self-contained. Itu akan menentukan permintaan sederhana objek yang menggunakan jendela
XMLHttpRequest
objek untuk membuat panggilan. Itu akan mendefinisikan sebuah fungsi sederhana untuk menunggu banyak janji-janji yang harus diselesaikan.Konteks. Contoh query Spotify Web API akhir dalam rangka untuk mencari
playlist
benda untuk satu set tertentu dari query string:Untuk setiap item, yang baru Berjanji akan memecat blok -
ExecutionBlock
, mengurai hasil, jadwal baru yang menjanjikan berdasarkan hasil array, yang merupakan daftar dari Spotifyuser
benda-benda dan mengeksekusi baru HTTP panggilan dalamExecutionProfileBlock
asynchronously.Anda kemudian dapat melihat bersarang Janji struktur, yang memungkinkan anda menelurkan beberapa dan benar-benar asynchronous bersarang HTTP panggilan, dan bergabung dengan hasil dari masing-masing subset dari panggilan melalui Janji
.semua
.CATATAN Baru-baru Spotify
pencarian
Api akan memerlukan akses token akan ditentukan dalam header permintaan:Jadi, anda untuk menjalankan contoh berikut anda harus menempatkan akses token anda di header permintaan:
Saya telah banyak membahas solusi ini di sini.
2017 jawaban: anda sekarang dapat melakukan apa yang anda inginkan dalam setiap browser saat ini dan node
Ini adalah cukup sederhana:
Berikut ini's bekerja versi dari kode anda:
menunggu didukung di semua browser yang ada saat ini dan node 8
It's masalah yang sangat umum yang kita hadapi saat berjuang dengan 'misteri' JavaScript. Biarkan aku mencoba menjelaskan misteri ini hari ini.
Let's mulai dengan sederhana fungsi JavaScript:
Yang's sederhana sinkron fungsi panggilan (di mana setiap baris dari kode 'selesai dengan tugasnya' sebelum yang berikutnya secara berurutan), dan hasilnya sama seperti yang diharapkan.
Sekarang mari's menambahkan sedikit twist, dengan memperkenalkan sedikit keterlambatan dalam fungsi kita, sehingga semua baris kode tidak 'selesai' dalam urutan. Dengan demikian, itu akan meniru perilaku asinkron fungsi :
Jadi di sana anda pergi, bahwa penundaan hanya patah fungsi yang kita harapkan! Tapi apa yang sebenarnya terjadi ? Nah, itu's benar-benar cukup logis jika anda melihat kode. fungsi
foo()
, setelah eksekusi, mengembalikan apa-apa (dengan demikian kembali nilaiundefined
), tetapi tidak memulai timer, yang menjalankan fungsi setelah 1s untuk kembali 'wohoo'. Tapi seperti yang anda lihat, nilai yang's ditugaskan untuk bar adalah segera kembali barang-barang dari foo(), tidak apa-apa lagi yang datang kemudian.Jadi, bagaimana kita mengatasi masalah ini?
Let's meminta kami fungsi untuk JANJI. Janji ini benar-benar tentang apa itu berarti : hal itu berarti bahwa fungsinya adalah untuk memberikan output apapun itu akan di masa depan. jadi let's melihat dalam tindakan untuk kami sedikit masalah di atas :
Dengan demikian, ringkasan - untuk mengatasi asynchronous fungsi seperti ajax berdasarkan panggilan dll., anda dapat menggunakan berjanji untuk
menyelesaikan
nilai (yang anda berniat untuk kembali). Dengan demikian, dalam waktu singkat anda mengatasi nilai bukan kembali ke, di asinkron fungsi.UPDATE (janji-Janji dengan async/menginap)
Selain menggunakan
lalu/menangkap
untuk bekerja dengan janji-janji, tidak ada satu pendekatan yang lebih. Idenya adalah untuk mengenali asynchronous fungsi dan kemudian menunggu janji-janji untuk menyelesaikan, sebelum pindah ke baris berikutnya kode. It's masih hanyajanji-janji
di bawah tenda, tapi dengan berbagai pendekatan sintaksis. Untuk membuat hal-hal yang lebih jelas, anda dapat menemukan perbandingan di bawah ini:kemudian/catch versi:
async/menunggu versi:
Anda dapat menggunakan kustom ini pustaka (ditulis dengan menggunakan Janji) untuk membuat panggilan jarak jauh.
Sederhana contoh penggunaan:
Solusi lain adalah untuk mengeksekusi kode melalui berurutan pelaksana nsynjs.
Jika fungsi ini promisified
nsynjs akan mengevaluasi semua janji-janji secara berurutan, dan menempatkan janji hasilnya menjadi
data
property:Jika fungsi ini tidak promisified
Langkah 1. Bungkus dengan fungsi callback ke nsynjs sadar-wrapper (jika memiliki promisified versi, anda dapat melewatkan langkah ini):
Langkah 2. Menempatkan logika sinkron ke dalam fungsi:
Langkah 3. Menjalankan fungsi secara sinkron melalui nsynjs:
Nsynjs akan mengevaluasi semua operator dan ekspresi langkah-demi-langkah, berhenti eksekusi dalam kasus jika hasil dari beberapa memperlambat fungsi yang tidak siap.
Banyak lagi contoh-contoh berikut ini: https://github.com/amaksr/nsynjs/tree/master/examples
Browser dapat dibagi menjadi tiga bagian:
1)Event Loop
2)Web API
3)Acara Antrian
Loop acara berjalan untuk selamanya aku.e jenis infinite loop.Peristiwa Antrian adalah tempat di mana semua fungsi yang mendorong pada beberapa peristiwa(contoh:click) ini adalah satu-persatu dibawa keluar dari antrian dan dimasukkan ke dalam loop Acara yang menjalankan fungsi ini dan mempersiapkan diri untuk yang berikutnya setelah yang pertama dilaksanakan.Ini berarti Pelaksanaan salah satu fungsi doesn't dimulai sampai fungsi sebelum di antrian dieksekusi dalam acara loop.
Sekarang mari kita berpikir kita mendorong dua fungsi dalam antrian adalah untuk mendapatkan data dari server dan lain memanfaatkan data tersebut.Kami mendorong serverRequest() fungsi dalam antrian pertama maka utiliseData() fungsi. serverRequest fungsi pergi dalam acara loop dan membuat panggilan ke server karena kita tidak pernah tahu berapa banyak waktu yang dibutuhkan untuk mendapatkan data dari server jadi proses ini diperkirakan akan memakan waktu dan jadi kita sibuk kami event loop dengan demikian gantung halaman kami, yang's dimana Web API datang ke peran itu mengambil ini fungsi dari loop acara dan penawaran dengan server membuat acara loop gratis sehingga kita dapat melaksanakan fungsi berikutnya dari antrian.Fungsi berikutnya dalam antrian adalah utiliseData() yang berjalan di lingkaran tetapi karena tidak ada data yang tersedia itu pergi limbah dan pelaksanaan fungsi berikutnya berlanjut sampai akhir antrian.(Ini disebut Async menelepon saya.e kita dapat melakukan sesuatu yang lain sampai kita mendapatkan data)
Biarkan kira kami serverRequest() fungsi telah kembali pernyataan dalam kode, ketika kita mendapatkan kembali data dari server Web API akan mendorong dalam antrian pada akhir antrian. Karena itu bisa mendorong pada akhir di antrian kita tidak bisa memanfaatkan data karena tidak ada fungsi yang tersisa di antrian kami untuk memanfaatkan data ini.Dengan demikian hal ini tidak mungkin untuk kembali sesuatu dari Async Panggilan.
Jadi Solusi untuk ini adalah panggil ulang atau janji.
Gambar dari salah satu jawaban berikut ini, menjelaskan dengan Benar callback digunakan... Kami memberikan fungsi(function memanfaatkan data yang dikembalikan dari server) untuk memanggil fungsi server.
Dalam Kode saya hal ini disebut sebagai
Baca di sini untuk metode baru dalam ECMA(2016/17) untuk membuat async panggilan(@Felix Kling Jawaban di Atas) https://stackoverflow.com/a/14220323/7579856