Bagaimana untuk mengembalikan respons daripada panggilan async?
P粉668113768
P粉668113768 2023-08-23 12:49:32
0
2
479

Bagaimana cara saya mengembalikan respons/hasil daripada fungsi foo

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 undefined< atau pembolehubah Nilai awal result.

Contoh fungsi tak segerak yang menerima panggilan balik (menggunakan fungsi ajax jQuery):

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 kemudian blok menggunakan Janji:

function foo() { hasil var; fetch(url).then(function(respons) { hasil = respons; // membalas respons; // <- Saya juga mencubanya }); pulangan hasil; // Ia sentiasa mengembalikan `tidak ditentukan` }


P粉668113768
P粉668113768

membalas semua (2)
P粉334721359

Jika andatidakmenggunakan jQuery dalam kod anda, jawapan ini adalah untuk anda

Kod anda sepatutnya kelihatan seperti ini:

function foo() { var httpRequest = new XMLHttpRequest(); httpRequest.open('GET', "/echo/json"); httpRequest.send(); return httpRequest.responseText; } var result = foo(); // Always ends up being 'undefined'

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 menggunakanfetchAPI 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:

function getFive(){ var a; setTimeout(function(){ a=5; },10); return a; }

(biola)

Disebabkana=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.

function onComplete(a){ // When the code completes, do this alert(a); } function getFive(whenDone){ var a; setTimeout(function(){ a=5; whenDone(a); },10); }

Ini dipanggilCPS. Pada asasnya, kami lulusgetFivetindakan 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:

getFive(onComplete);

"5" akan muncul pada skrin.(biola).

Penyelesaian yang mungkin

Pada asasnya terdapat dua cara untuk menyelesaikan masalah ini:

  1. Jadikan panggilan AJAX segerak (kami memanggilnya SJAX).
  2. Faktor semula kod anda untuk berfungsi dengan betul dengan panggilan balik.

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:

var request = new XMLHttpRequest(); request.open('GET', 'yourURL', false); // `false` makes the request synchronous request.send(null); if (request.status === 200) {// That's HTTP for 'ok' console.log(request.responseText); }

2. Susun semula kod

Jadikan fungsi anda menerima panggilan balik. Dalam kod contoh, anda boleh memberitahu bagaimanafoo接受回调。我们将告诉代码当foobertindak balasapabilaselesai.

Jadi:

var result = foo(); // Code that depends on `result` goes here

menjadi:

foo(function(result) { // Code that depends on `result` });

Di sini kami menghantar fungsi tanpa nama, tetapi kami boleh menghantar rujukan kepada fungsi sedia ada dengan mudah, menjadikannya kelihatan seperti:

function myHandler(result) { // Code that depends on `result` } foo(myHandler);

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

function foo(callback) { var httpRequest = new XMLHttpRequest(); httpRequest.onload = function(){ // When the request is loaded callback(httpRequest.responseText);// We're calling our method }; httpRequest.open('GET', "/echo/json"); httpRequest.send(); }

(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.

    P粉642920522

    Soalan

    AdalamAjaxbermaksudasynchronous. Ini bermakna menghantar permintaan (atau sebaliknya menerima respons) dialih keluar daripada aliran pelaksanaan biasa. Dalam contoh anda,$.ajax立即返回,并且下一条语句return result;在您作为successpanggilan 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":

    function findItem() { var item; while(item_not_found) { // search } return item; } var item = findItem(); // Do something with item doSomethingElse();

    Walaupun sebarang kod selepasfindItem可能需要很长时间才能执行,但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.

    findItem(function(item) { // Do something with the item }); doSomethingElse();

    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:

    • Janji denganasync/await(ES2017+, berfungsi dalam pelayar lama jika anda menggunakan transpiler atau penjana semula)
    • Panggil balik(popular dalam nod)
    • Denganthen() 的 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+: Gunakanasync/await 进行承诺

    Keluaran ECMAScript 2017 memperkenalkansokongan peringkat sintaksuntuk fungsi tak segerak. Denganasyncawaitanda boleh menulis secara tak segerak dalam "gaya segerak". Kod tersebut masih tidak segerak, tetapi lebih mudah dibaca/difahami.

    async/await构建在 Promise 之上:async函数始终返回 Promise。awaitDibina atas Janji: Fungsi

    async sentiasa mengembalikan Janji.

    tunggu "membuka" Janji dan sama ada menghasilkan nilai yang Janji selesaikan, atau melemparkan ralat jika Janji ditolak.async函数或JavaScript 模块。模块外部不支持顶级await,因此您可能必须创建异步 IIFE (立即调用函数表达式)来启动异步PENTING

    : Anda hanya boleh menggunakan

    tunggu dalam fungsiasync ataumodul JavaScript. Peringkat teratas tunggutidak 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

    async

    danfindItem()menunggu

    .Berikut ialah contoh yang memperincikan fungsitertundaasync/awaitfindItem() di atas:

    // Using 'superagent' which will return a promise. var superagent = require('superagent') // This is isn't declared as `async` because it already returns a promise function delay() { // `delay` returns a promise return new Promise(function(resolve, reject) { // Only `delay` is able to resolve or reject the promise setTimeout(function() { resolve(42); // After 3 seconds, resolve the promise with value 42 }, 3000); }); } async function getAllBooks() { try { // GET a list of book IDs of the current user var bookIDs = await superagent.get('/user/books'); // wait for 3 seconds (just for the sake of this example) await delay(); // GET information about each book return superagent.get('/books/ids='+JSON.stringify(bookIDs)); } catch(error) { // If any of the awaited promises was rejected, this catch block // would catch the rejection reason return null; } } // Start an IIFE to use `await` at the top level (async function(){ let books = await getAllBooks(); console.log(books); })();
    Versi pelayardan

    nod
    semasa menyokong

    . Anda juga boleh menukar kod anda kepada ES5 dengan bantuan regenerator

    (atau alatan yang menggunakan regenerator) untuk menyokong persekitaran yang lebih lama seperti

    Babel

    ). 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 membuatfoo接受回调并将其用作successpanggilan balik. Jadi ini

    var result = foo(); // Code that depends on 'result'

    menjadi

    foo(function(result) { // Code that depends on 'result' });

    Di sini kami mentakrifkan fungsi "sebaris", tetapi anda boleh lulus mana-mana rujukan fungsi:

    function myCallback(result) { // Code that depends on 'result' } foo(myCallback);

    fooitu sendiri ditakrifkan seperti berikut:

    function foo(callback) { $.ajax({ // ... success: callback }); }

    panggil balik akan merujuk fungsi yang kami hantar ke callback将引用我们调用时传递给 foo的函数,并将其传递给 success。 IE。一旦Ajax请求成功, $.ajax将调用 callback并将响应传递给回调(可以用 resultapabila kami memanggilnya dan menghantarnya kepada kejayaan. iaitu. Setelah permintaan Ajax berjaya, $.ajaxakan memanggil callbackdan menghantar respons kepada panggilan balik (yang boleh dirujuk dengan result, sejak begitulah cara kita mentakrifkan panggilan balik The way).

    Anda juga boleh memproses respons sebelum menghantarnya ke panggilan balik:

    function foo(callback) { $.ajax({ // ... success: function(response) { // For example, filter the response callback(filtered_response); } }); }

    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:

    function delay() { // `delay` returns a promise return new Promise(function(resolve, reject) { // Only `delay` is able to resolve or reject the promise setTimeout(function() { resolve(42); // After 3 seconds, resolve the promise with value 42 }, 3000); }); } delay() .then(function(v) { // `delay` returns a promise console.log(v); // Log the value once it is resolved }) .catch(function(v) { // Or do something else if it is rejected // (it would not happen in this example, since `reject` is not called). });
    .as-console-wrapper { max-height: 100% !important; top: 0; }
      Muat turun terkini
      Lagi>
      kesan web
      Kod sumber laman web
      Bahan laman web
      Templat hujung hadapan
      Tentang kita Penafian Sitemap
      Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!