Pertanyaan Bagaimana cara mengembalikan respons dari panggilan asynchronous?


Saya punya fungsi foo yang membuat permintaan Ajax. Bagaimana saya bisa mengembalikan respon dari foo?

Saya mencoba mengembalikan nilai dari success panggil balik serta menetapkan respons terhadap variabel lokal di dalam fungsi dan mengembalikan yang satu itu, tetapi tidak satu pun dari cara-cara itu benar-benar mengembalikan respons.

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

4307
2018-01-08 17:06


asal


Jawaban:


-> Untuk penjelasan yang lebih umum tentang perilaku asinkron dengan contoh yang berbeda, silakan lihat  Mengapa variabel saya tidak berubah setelah saya memodifikasinya di dalam suatu fungsi? - Referensi kode asinkron 

-> Jika Anda sudah memahami masalahnya, lompat ke solusi yang mungkin di bawah ini.

Masalah

Itu SEBUAH di Ajax berdiri untuk asynchronous . Itu berarti mengirim permintaan (atau lebih tepatnya menerima tanggapan) diambil dari aliran eksekusi normal. Dalam contoh Anda, $.ajax segera kembali dan pernyataan berikutnya, return result;, dijalankan sebelum fungsi yang Anda lewati success callback bahkan disebut.

Berikut adalah analogi yang semoga membuat perbedaan antara aliran sinkron dan asynchronous yang lebih jelas:

Sinkronis

Bayangkan Anda membuat panggilan telepon ke teman dan memintanya untuk mencari sesuatu untuk Anda. Meskipun mungkin butuh waktu beberapa saat, Anda menunggu di telepon dan menatap ke luar angkasa, sampai teman Anda memberi Anda jawaban yang Anda butuhkan.

Hal yang sama terjadi ketika Anda membuat panggilan fungsi yang berisi kode "normal":

function findItem() {
    var item;
    while(item_not_found) {
        // search
    }
    return item;
}

var item = findItem();

// Do something with item
doSomethingElse();

Meskipun findItem mungkin butuh waktu lama untuk mengeksekusi, kode apa pun yang datang setelahnya var item = findItem(); harus Tunggu sampai fungsi mengembalikan hasilnya.

Asynchronous

Anda menelepon teman Anda lagi karena alasan yang sama. Tetapi kali ini Anda mengatakan kepadanya bahwa Anda sedang terburu-buru dan dia seharusnya menelepon Anda kembali di ponsel Anda. Anda menutup telepon, meninggalkan rumah dan melakukan apa pun yang Anda rencanakan. Begitu teman Anda menelepon Anda kembali, Anda berurusan dengan informasi yang ia berikan kepada Anda.

Itulah yang terjadi ketika Anda melakukan permintaan Ajax.

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

Alih-alih menunggu tanggapan, eksekusi berlanjut segera dan pernyataan setelah panggilan Ajax dijalankan. Untuk mendapatkan respons akhirnya, Anda memberikan fungsi untuk dipanggil setelah respons diterima, a panggilan balik (perhatikan sesuatu? menelepon kembali ?). Pernyataan apa pun yang muncul setelah panggilan itu dijalankan sebelum panggilan balik dipanggil.


Solusi)

Merangkul sifat asynchronous dari JavaScript! Sementara operasi asynchronous tertentu menyediakan synchronous counterparts (begitu juga "Ajax"), umumnya tidak disarankan untuk menggunakannya, terutama dalam konteks browser.

Kenapa itu buruk?

JavaScript berjalan di utas UI browser dan proses yang berjalan lama akan mengunci UI, membuatnya 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 pengalaman pengguna yang buruk. Pengguna tidak akan dapat mengetahui apakah semuanya berfungsi dengan baik atau tidak. Selanjutnya, efeknya akan lebih buruk bagi pengguna dengan koneksi yang lambat.

Berikut ini kami akan melihat tiga solusi berbeda yang semuanya dibangun di atas satu sama lain:

  • Janji dengan async/await (ES2017 +, tersedia di browser lama jika Anda menggunakan transpiler atau regenerator)
  • Callback (Populer di node)
  • Janji dengan then() (ES2015 +, tersedia di browser lama jika Anda menggunakan salah satu dari banyak perpustakaan janji)

Ketiganya tersedia di browser saat ini, dan simpul 7+. 


ES2017 +: Janji dengan async/await

Versi ECMAScript yang baru dirilis pada tahun 2017 diperkenalkan dukungan tingkat sintaks untuk fungsi asynchronous. Dengan bantuan dari async dan await, Anda dapat menulis asynchronous dalam "gaya sinkron". Jangan salah lagi: Kode ini masih asynchronous, tetapi lebih mudah dibaca / dipahami.

async/await membangun di atas janji: sebuah async fungsi selalu mengembalikan janji. await "membukanya" janji dan menghasilkan nilai janji itu diselesaikan dengan atau melempar kesalahan jika janji itu ditolak.

Penting: Anda hanya bisa menggunakan await di dalam sebuah async fungsi. Itu berarti bahwa pada tingkat paling atas, Anda masih harus bekerja langsung dengan janji itu.

Anda dapat membaca lebih lanjut tentang async dan await di MDN.

Berikut ini contoh yang dibangun di atas keterlambatan 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 a second (just for the sake of this example)
    await delay(1000);
    // GET information about each book
    return await 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;
  }
}

// Async functions always return a promise
getAllBooks()
  .then(function(books) {
    console.log(books);
  });

Lebih baru browser dan simpul dukungan versi async/await. Anda juga dapat mendukung lingkungan yang lebih tua dengan mengubah kode Anda ke ES5 dengan bantuan regenerator (atau alat yang menggunakan regenerator, seperti Babel).


Biarkan fungsi diterima panggilan balik

Callback hanyalah sebuah fungsi yang dilewatkan ke fungsi lain. Fungsi lain itu bisa memanggil fungsi berlalu kapan pun siap. Dalam konteks proses asynchronous, callback akan dipanggil setiap kali proses asynchronous dilakukan. Biasanya, hasilnya diteruskan ke panggilan balik.

Dalam contoh pertanyaan, Anda bisa membuatnya foo menerima panggilan balik dan menggunakannya sebagai success panggilan balik. Jadi ini

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

menjadi

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

Di sini kami mendefinisikan fungsi "inline" tetapi Anda dapat meneruskan referensi fungsi apa pun:

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

foo(myCallback);

foo itu sendiri didefinisikan sebagai berikut:

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

callback akan mengacu pada fungsi yang kita lewati foo ketika kami menyebutnya dan kami meneruskannya begitu saja success. Yaitu. setelah permintaan Ajax berhasil, $.ajax akan menelepon callback dan meneruskan respons ke callback (yang bisa disebut dengan result, karena ini adalah bagaimana kami mendefinisikan callback).

Anda juga dapat memproses tanggapan sebelum meneruskannya ke callback:

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

Lebih mudah menulis kode menggunakan callback daripada yang terlihat. Setelah semua, JavaScript di browser sangat event-driven (acara DOM). Menerima respons Ajax tidak lain hanyalah sebuah acara.
Kesulitan bisa timbul ketika Anda harus bekerja dengan kode pihak ketiga, tetapi sebagian besar masalah dapat diselesaikan dengan hanya memikirkan alur aplikasi.


ES2015 +: Janji dengan kemudian()

Itu API Janji adalah fitur baru ECMAScript 6 (ES2015), tetapi memiliki fitur yang bagus dukungan browser sudah. Ada juga banyak pustaka yang menerapkan API Janji standar dan menyediakan metode tambahan untuk mempermudah penggunaan dan komposisi fungsi asinkron (mis. burung biru).

Janji-janji adalah wadah untuk masa depan nilai-nilai. Ketika janji menerima nilai (itu adalah terselesaikan) atau ketika dibatalkan (ditolak), ini memberitahukan semua "pendengar" yang ingin mengakses nilai ini.

Keuntungan lebih dari callback biasa adalah bahwa mereka memungkinkan Anda untuk memisahkan kode Anda dan mereka lebih mudah untuk menulis.

Berikut ini contoh sederhana menggunakan janji:

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).
  });

Diterapkan pada panggilan Ajax kami, kami dapat menggunakan janji-janji seperti ini:

function ajax(url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      resolve(this.responseText);
    };
    xhr.onerror = reject;
    xhr.open('GET', url);
    xhr.send();
  });
}

ajax("/echo/json")
  .then(function(result) {
    // Code depending on result
  })
  .catch(function() {
    // An error occurred
  });

Menggambarkan semua keuntungan yang ditawarkan janji berada di luar lingkup jawaban ini, tetapi jika Anda menulis kode baru, Anda harus mempertimbangkannya dengan serius. Mereka memberikan abstraksi yang hebat dan pemisahan kode Anda.

Informasi lebih lanjut tentang janji: Batuan HTML5 - Janji JavaScript

Catatan sampingan: objek ditangguhkan jQuery

Objek yang ditangguhkan adalah implementasi jQuery atas janji-janji (sebelum API Janji dibakukan). Mereka berperilaku hampir seperti janji tetapi mengekspos API yang sedikit berbeda.

Setiap metode jQuery Ajax sudah mengembalikan "objek yang ditangguhkan" (sebenarnya merupakan janji dari objek yang ditangguhkan) yang dapat Anda kembalikan dari fungsi Anda:

function ajax() {
    return $.ajax(...);
}

ajax().done(function(result) {
    // Code depending on result
}).fail(function() {
    // An error occurred
});

Catatan sampingan: Berjanjilah gotchas

Perlu diingat bahwa janji dan objek yang ditangguhkan adalah adil kontainer untuk nilai masa depan, mereka bukan nilai itu sendiri. Misalnya, Anda memiliki yang berikut:

function checkPassword() {
    return $.ajax({
        url: '/password',
        data: {
            username: $('#username').val(),
            password: $('#password').val()
        },
        type: 'POST',
        dataType: 'json'
    });
}

if (checkPassword()) {
    // Tell the user they're logged in
}

Kode ini salah memahami masalah asinkron di atas. Secara khusus, $.ajax() tidak membekukan kode saat memeriksa halaman '/ kata sandi' di server Anda - ia mengirim permintaan ke server dan ketika menunggu, segera mengembalikan objek Ajax Deferred jQuery, bukan respons dari server. Itu artinya if pernyataan akan selalu mendapatkan objek Ditangguhkan ini, perlakukan sebagai true, dan melanjutkan seolah-olah pengguna login. Tidak baik.

Tetapi perbaikannya mudah:

checkPassword()
.done(function(r) {
    if (r) {
        // Tell the user they're logged in
    } else {
        // Tell the user their password was bad
    }
})
.fail(function(x) {
    // Tell the user something bad happened
});

Tidak disarankan: Sinkronisasi "Ajax" memanggil

Seperti yang saya sebutkan, beberapa (!) Operasi asynchronous memiliki mitra yang sinkron. Saya tidak menganjurkan penggunaannya, tetapi demi kelengkapan, di sini adalah bagaimana Anda akan melakukan panggilan sinkron:

Tanpa jQuery

Jika Anda langsung menggunakan XMLHTTPRequest objek, lulus false sebagai argumen ketiga .open.

jQuery

Jika Anda menggunakan jQuery, Anda dapat mengatur async opsi untuk false. Perhatikan bahwa opsi ini tidak lagi digunakan sejak jQuery 1.8. Anda kemudian dapat menggunakan a success panggil balik atau akses responseText milik dari objek jqXHR:

function foo() {
    var jqXHR = $.ajax({
        //...
        async: false
    });
    return jqXHR.responseText;
}

Jika Anda menggunakan metode Ajax jQuery lainnya, seperti $.get, $.getJSON, dll., Anda harus mengubahnya menjadi $.ajax(karena Anda hanya bisa meneruskan parameter konfigurasi ke $.ajax).

Perhatian! Tidak mungkin membuat sinkron JSONP permintaan. JSONP karena sifatnya selalu asinkron (satu lagi alasan untuk tidak mempertimbangkan opsi ini).


4654
2018-01-08 17:06



Jika kamu tidak menggunakan jQuery dalam kode Anda, jawaban ini untuk Anda

Kode Anda harus menjadi sesuatu yang sesuai dengan 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 pekerjaan yang baik dengan menulis jawaban untuk orang yang menggunakan jQuery untuk AJAX, saya memutuskan untuk memberikan alternatif bagi orang yang tidak.

(Catatan, bagi yang menggunakan yang baru fetch API, Angular, atau janji saya telah menambahkan jawaban lain di bawah ini)


Apa yang kamu hadapi

Ini adalah ringkasan singkat dari "Penjelasan masalah" dari jawaban lainnya, jika Anda tidak yakin setelah membaca ini, baca itu.

Itu SEBUAH dalam singkatan AJAX asynchronous. Itu berarti mengirim permintaan (atau lebih tepatnya menerima tanggapan) diambil dari aliran eksekusi normal. Dalam contoh Anda, .send segera kembali dan pernyataan berikutnya, return result;, dijalankan sebelum fungsi yang Anda lewati success callback bahkan disebut.

Ini berarti ketika Anda kembali, pendengar yang Anda tetapkan belum mengeksekusi, yang berarti nilai yang Anda kembalikan belum ditentukan.

Ini adalah analogi sederhana

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

(Biola)

Nilai dari a kembali adalah undefined sejak itu a=5 bagian belum dieksekusi. AJAX bertindak seperti ini, Anda mengembalikan nilai sebelum server mendapat kesempatan untuk memberi tahu browser Anda berapa nilai itu.

Salah satu solusi yang mungkin untuk masalah ini adalah kode aktif kembali , memberi tahu program Anda apa yang harus dilakukan ketika perhitungan 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 disebut CPS. Pada dasarnya, kita sedang lewat getFive suatu tindakan yang harus dilakukan ketika selesai, kami memberi tahu kode kami bagaimana bereaksi ketika suatu acara selesai (seperti panggilan AJAX kami, atau dalam hal ini batas waktu).

Penggunaannya adalah:

getFive(onComplete);

Yang harus mengingatkan "5" ke layar. (Biola).

Solusi yang memungkinkan

Pada dasarnya ada dua cara untuk menyelesaikan ini:

  1. Buat panggilan AJAX sinkron (sebut saja SJAX).
  2. Atur ulang kode Anda agar berfungsi dengan baik dengan callback.

1. Synchronous AJAX - Jangan lakukan itu !!

Adapun AJAX sinkron, jangan lakukan itu! Jawaban Felix menimbulkan beberapa argumen yang meyakinkan tentang mengapa itu ide yang buruk. Untuk merangkumnya, itu akan membekukan browser pengguna sampai server mengembalikan respons dan menciptakan pengalaman pengguna yang sangat buruk. Berikut ini ringkasan singkat lain yang diambil dari MDN tentang alasannya:

XMLHttpRequest mendukung komunikasi sinkron dan asinkron. Secara umum, bagaimanapun, permintaan asynchronous harus lebih disukai untuk permintaan sinkron untuk alasan kinerja.

Singkatnya, permintaan sinkron memblokir eksekusi kode ... ... ini dapat menyebabkan masalah serius ...

Jika kamu memiliki untuk melakukannya, Anda dapat mengoper bendera: Beginilah caranya:

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. Restrukturisasi kode

Biarkan fungsi Anda menerima panggilan balik. Dalam kode contoh foo dapat dibuat untuk menerima panggilan balik. Kami akan memberi tahu kode cara kami reaksi kapan foo selesai.

Begitu:

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

Menjadi:

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

Di sini kami melewati fungsi anonim, tetapi kami dapat dengan mudah melewati referensi ke fungsi yang ada, membuatnya terlihat seperti:

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

Untuk detail lebih lanjut tentang bagaimana desain panggilan balik semacam ini dilakukan, periksa jawaban Felix.

Sekarang, mari kita mendefinisikan foo sendiri untuk bertindak sesuai

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)

Kami sekarang telah membuat fungsi foo kami menerima tindakan untuk dijalankan ketika AJAX selesai dengan sukses, kami dapat memperluas ini lebih lanjut dengan memeriksa apakah status respon tidak 200 dan bertindak sesuai (membuat penangan gagal dan semacamnya). Secara efektif menyelesaikan masalah kami.

Jika Anda masih kesulitan memahami ini baca panduan memulai AJAX di MDN.


886
2018-05-29 23:30



XMLHttpRequest 2 (pertama-tama baca jawaban dari Benjamin Gruenbaum & Felix Kling)

Jika Anda tidak menggunakan jQuery dan menginginkan XMLHttpRequest 2 singkat yang bagus yang berfungsi pada browser modern dan juga pada browser seluler, saya sarankan untuk menggunakannya dengan cara ini:

function ajax(a, b, c){ // URL, callback, just a placeholder
  c = new XMLHttpRequest;
  c.open('GET', a);
  c.onload = b;
  c.send()
}

Seperti yang Anda lihat:

  1. Lebih singkat dari semua fungsi lain yang Terdaftar.
  2. Callback diatur secara langsung (jadi tidak ada tambahan yang tidak perlu ditutup).
  3. Ini menggunakan onload baru (jadi Anda tidak perlu memeriksa status readystate &&)
  4. Ada beberapa situasi lain yang saya tidak ingat yang membuat XMLHttpRequest 1 menjengkelkan.

Ada dua cara untuk mendapatkan respons dari panggilan Ajax ini (tiga menggunakan nama var XMLHttpRequest):

Yang paling sederhana:

this.response

Atau jika karena alasan tertentu Anda bind() panggilan balik ke kelas:

e.target.response

Contoh:

function callback(e){
  console.log(this.response);
}
ajax('URL', callback);

Atau (yang di atas adalah fungsi anonim yang lebih baik selalu menjadi masalah):

ajax('URL', function(e){console.log(this.response)});

Tidak ada yang lebih mudah.

Sekarang beberapa orang mungkin akan mengatakan bahwa lebih baik menggunakan onreadystatechange atau bahkan nama variabel XMLHttpRequest. Itu salah.

Periksa Fitur lanjutan XMLHttpRequest

Ini didukung pada semua * browser modern. Dan saya dapat mengonfirmasi karena saya menggunakan pendekatan ini karena XMLHttpRequest 2 ada. Saya tidak pernah mengalami masalah apa pun di semua browser yang saya gunakan.

onreadystatechange hanya berguna jika Anda ingin mendapatkan header pada status 2.

Menggunakan XMLHttpRequest nama variabel adalah kesalahan besar lainnya saat Anda perlu menjalankan callback di dalam penutup onload / oreadystatechange jika Anda kehilangannya.


Sekarang jika Anda menginginkan sesuatu yang lebih kompleks menggunakan pos dan FormData, Anda dapat dengan mudah memperluas fungsi ini:

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val},placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.send(d||null)
}

Sekali lagi ... itu fungsi yang sangat singkat, tetapi tidak mendapatkan & memposting.

Contoh penggunaan:

x(url, callback); // By default it's get so no need to set
x(url, callback, 'post', {'key': 'val'}); // No need to set post data

Atau berikan elemen formulir lengkap (document.getElementsByTagName('form')[0]):

var fd = new FormData(form);
x(url, callback, 'post', fd);

Atau tetapkan beberapa nilai khusus:

var fd = new FormData();
fd.append('key', 'val')
x(url, callback, 'post', fd);

Seperti yang Anda lihat, saya tidak menerapkan sinkronisasi ... itu hal yang buruk.

Setelah mengatakan itu ... mengapa tidak melakukannya dengan cara yang mudah?


Seperti disebutkan dalam komentar penggunaan kesalahan & & sinkron benar-benar memecahkan titik jawaban. Yang merupakan cara singkat yang bagus untuk menggunakan Ajax dengan cara yang benar?

Penangan kesalahan

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val}, placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.onerror = error;
  c.send(d||null)
}

function error(e){
  console.log('--Error--', this.type);
  console.log('this: ', this);
  console.log('Event: ', e)
}
function displayAjax(e){
  console.log(e, this);
}
x('WRONGURL', displayAjax);

Dalam skrip di atas, Anda memiliki pengendali kesalahan yang didefinisikan secara statis sehingga tidak membahayakan fungsi. Penangan kesalahan dapat digunakan untuk fungsi lain juga.

Tetapi untuk benar-benar mengeluarkan kesalahan tersebut hanya caranya adalah dengan menulis URL yang salah dalam hal ini setiap browser melempar kesalahan.

Penangan kesalahan mungkin berguna jika Anda mengatur header khusus, mengatur responseType ke buffer array blob atau apa pun ....

Bahkan jika Anda lulus 'POSTAPAPAP' sebagai metode itu tidak akan menimbulkan kesalahan.

Bahkan jika Anda melewatkan 'fdggdgilfdghfldj' sebagai formdata, itu tidak akan membuat kesalahan.

Dalam kasus pertama kesalahan ada di dalam displayAjax() dibawah this.statusText sebagai Method not Allowed.

Dalam kasus kedua, itu hanya berfungsi. Anda harus memeriksa di sisi server jika Anda melewati data posting yang benar.

lintas-domain tidak diizinkan melempar kesalahan secara otomatis.

Dalam respons kesalahan, tidak ada kode kesalahan.

Hanya ada this.type yang diatur ke kesalahan.

Mengapa menambahkan pengendali kesalahan jika Anda sama sekali tidak memiliki kontrol atas kesalahan? Sebagian besar kesalahan dikembalikan di dalam ini dalam fungsi panggilan balik displayAjax().

Jadi: Tidak perlu memeriksa kesalahan jika Anda dapat menyalin dan menempel URL dengan benar. ;)

PS: Seperti tes pertama saya menulis x ('x', displayAjax) ..., dan itu benar-benar mendapat jawaban ... ??? Jadi saya memeriksa folder tempat HTML berada, dan ada file bernama 'x.xml'. Jadi bahkan jika Anda lupa ekstensi file Anda, XMLHttpRequest 2 AKAN MENEMUKANNYA. Saya LOL


Baca file yang sinkron

Jangan lakukan itu.

Jika Anda ingin memblokir browser untuk sementara waktu memuat file txt besar yang besar sinkron.

function omg(a, c){ // URL
  c = new XMLHttpRequest;
  c.open('GET', a, true);
  c.send();
  return c; // Or c.response
}

Sekarang Anda bisa melakukannya

 var res = omg('thisIsGonnaBlockThePage.txt');

Tidak ada cara lain untuk melakukan ini dengan cara non-asynchronous. (Ya, dengan setTimeout loop ... tapi serius?)

Hal lain adalah ... jika Anda bekerja dengan API atau hanya Anda memiliki file daftar atau apa pun yang Anda selalu menggunakan fungsi yang berbeda untuk setiap permintaan ...

Hanya jika Anda memiliki halaman tempat Anda memuat selalu XML / JSON yang sama atau apa pun yang Anda perlukan hanya satu fungsi. Dalam hal ini, ubah sedikit fungsi Ajax dan gantikan b dengan fungsi khusus Anda.


Fungsi di atas adalah untuk penggunaan dasar.

Jika Anda ingin MEMPERPANJANG fungsi ...

Ya kamu bisa.

Saya menggunakan banyak API dan salah satu fungsi pertama yang saya integrasikan ke setiap halaman HTML adalah fungsi Ajax pertama dalam jawaban ini, dengan GET saja ...

Tetapi Anda dapat melakukan banyak hal dengan XMLHttpRequest 2:

Saya membuat pengelola unduhan (menggunakan rentang di kedua sisi dengan resume, filereader, filesystem), berbagai konverter penukar gambar menggunakan kanvas, mengisi database websql dengan base64images dan banyak lagi ... Tetapi dalam kasus ini Anda harus membuat fungsi hanya untuk tujuan itu ... kadang-kadang Anda memerlukan gumpalan, buffer array, Anda dapat mengatur header, menimpa mimetype dan ada banyak lagi ...

Tapi pertanyaannya di sini adalah bagaimana mengembalikan respons Ajax ... (Saya menambahkan cara yang mudah.)


302
2017-08-19 08:06



Jika Anda menggunakan janji, jawaban ini untuk Anda.

Ini berarti AngularJS, jQuery (dengan ditangguhkan), pengganti XHR asli (fetch), EmberJS, BackboneJS's save atau sembarang pustaka node yang mengembalikan janji.

Kode Anda harus menjadi sesuatu yang sesuai dengan ini:

function foo() {
    var data;
    // or $.get(...).then, or request(...).then, or query(...).then
    fetch("/echo/json").then(function(response){
        data = response.json();
    });
    return data;
}

var result = foo(); // result is always undefined no matter what.

Felix Kling melakukan pekerjaan yang baik dengan menulis jawaban untuk orang yang menggunakan jQuery dengan callback untuk AJAX. Saya punya jawaban untuk XHR asli. Jawaban ini untuk penggunaan umum janji baik di frontend atau backend.


Masalah inti

Model konkurensi JavaScript di browser dan di server dengan NodeJS / io.js adalah asynchronous dan reaktif.

Setiap kali Anda memanggil metode yang mengembalikan janji, then penangan adalah selalu dijalankan secara asinkron - yaitu, setelah kode di bawah mereka yang tidak dalam .then pawang

Ini berarti ketika Anda kembali data itu then pawang yang Anda tetapkan belum melakukan eksekusi. Ini pada gilirannya berarti bahwa nilai yang Anda kembalikan belum ditetapkan ke nilai yang tepat pada waktunya.

Berikut adalah analogi sederhana untuk masalah ini:

    function getFive(){
        var data;
        setTimeout(function(){ // set a timer for one second in the future
           data = 5; // after a second, do this
        }, 1000);
        return data;
    }
    document.body.innerHTML = getFive(); // `undefined` here and not 5

Nilai dari data aku s undefined sejak itu data = 5 bagian belum dieksekusi. Kemungkinan akan dieksekusi dalam detik tetapi pada saat itu tidak relevan dengan nilai yang dikembalikan.

Karena operasi belum terjadi (AJAX, panggilan server, IO, pewaktu), Anda mengembalikan nilai sebelum permintaan mendapat kesempatan untuk memberi tahu kode Anda berapa nilai itu.

Salah satu solusi yang mungkin untuk masalah ini adalah kode aktif kembali , memberi tahu program Anda apa yang harus dilakukan ketika perhitungan selesai. Janji-janji aktif mengaktifkan ini dengan menjadi temporal (waktu-sensitif) di alam.

Rekapitulasi cepat tentang janji

Janji adalah a nilai dari waktu ke waktu. Janji memiliki status, mereka mulai tertunda tanpa nilai dan dapat diselesaikan:

  • terpenuhi yang berarti bahwa perhitungan selesai dengan sukses.
  • ditolak artinya komputasi gagal.

Janji hanya bisa mengubah negara sekali setelah itu akan selalu berada pada kondisi yang sama selamanya. Anda dapat melampirkan then penangan untuk berjanji mengekstrak nilai mereka dan menangani kesalahan. then penangan memungkinkan chaining panggilan telepon. Janji dibuat oleh menggunakan API yang mengembalikannya. Misalnya, pengganti AJAX yang lebih modern fetch atau jQuery $.get kembalikan janji.

Saat kami menelepon .then pada sebuah janji dan kembali sesuatu dari itu - kita mendapatkan janji untuk itu nilai yang diproses. Jika kita mengembalikan janji lain, kita akan mendapatkan hal-hal luar biasa, tapi mari kita tahan kuda kita.

Dengan janji

Mari kita lihat bagaimana kita bisa menyelesaikan masalah di atas dengan janji. Pertama, mari kita mendemonstrasikan pemahaman kita tentang status janji dari atas dengan menggunakan Janji konstruktor untuk membuat fungsi tunda:

function delay(ms){ // takes amount of milliseconds
    // returns a new promise
    return new Promise(function(resolve, reject){
        setTimeout(function(){ // when the time is up
            resolve(); // change the promise to the fulfilled state
        }, ms);
    });
}

Sekarang, setelah kami mengonversi setTimeout untuk menggunakan janji, kita dapat menggunakannya then untuk membuatnya terhitung:

function delay(ms){ // takes amount of milliseconds
  // returns a new promise
  return new Promise(function(resolve, reject){
    setTimeout(function(){ // when the time is up
      resolve(); // change the promise to the fulfilled state
    }, ms);
  });
}

function getFive(){
  // we're RETURNING the promise, remember, a promise is a wrapper over our value
  return delay(100).then(function(){ // when the promise is ready
      return 5; // return the value 5, promises are all about return values
  })
}
// we _have_ to wrap it like this in the call site, we can't access the plain value
getFive().then(function(five){ 
   document.body.innerHTML = five;
});

Pada dasarnya, daripada mengembalikan a nilai yang tidak bisa kita lakukan karena model konkurensi - kita kembali a pembungkus untuk nilai yang kami bisa membuka dengan then. Ini seperti kotak yang bisa Anda buka then.

Menerapkan ini

Ini sama dengan panggilan API asli Anda, Anda dapat:

function foo() {
    // RETURN the promise
    return fetch("/echo/json").then(function(response){
        return response.json(); // process it inside the `then`
    });
}

foo().then(function(response){
    // access the value inside the `then`
})

Jadi ini juga berfungsi dengan baik. Kami telah belajar bahwa kami tidak dapat mengembalikan nilai dari panggilan yang tidak sinkron, tetapi kami dapat menggunakan janji dan menghubungkannya untuk melakukan pemrosesan. Kami sekarang tahu cara mengembalikan respons dari panggilan asynchronous.

ES2015 (ES6)

ES6 memperkenalkan generator yang merupakan fungsi yang dapat kembali di tengah dan kemudian melanjutkan kembali titik di mana mereka berada. Ini biasanya berguna untuk urutan, misalnya:

function* foo(){ // notice the star, this is ES6 so new browsers/node/io only
    yield 1;
    yield 2;
    while(true) yield 3;
}

Merupakan fungsi yang mengembalikan sebuah iterator secara berurutan 1,2,3,3,3,3,.... yang bisa di-iterasi. Meskipun ini menarik dengan sendirinya dan membuka ruang untuk banyak kemungkinan ada satu kasus yang menarik.

Jika urutan yang kita hasilkan adalah urutan tindakan dan bukan angka - kita dapat menghentikan sementara fungsi ketika suatu tindakan dihasilkan dan menunggunya sebelum kita melanjutkan fungsi. Jadi daripada urutan angka, kita perlu urutan masa depan nilai - yaitu: janji.

Trik yang agak rumit namun sangat kuat ini memungkinkan kita menulis kode asinkron dengan cara yang sinkron. Ada beberapa "pelari" yang melakukan ini untuk Anda, menulis satu adalah beberapa baris kode pendek tetapi di luar lingkup jawaban ini. Saya akan menggunakan Bluebird's Promise.coroutine di sini, tetapi ada pembungkus lain seperti co atau Q.async.

var foo = coroutine(function*(){
    var data = yield fetch("/echo/json"); // notice the yield
    // code here only executes _after_ the request is done
    return data.json(); // data is defined
});

Metode ini mengembalikan janji itu sendiri, yang dapat kita konsumsi dari coroutines lainnya. Sebagai contoh:

var main = coroutine(function*(){
   var bar = yield foo(); // wait our earlier coroutine, it returns a promise
   // server call done here, code below executes when done
   var baz = yield fetch("/api/users/"+bar.userid); // depends on foo's result
   console.log(baz); // runs after both requests done
});
main();

ES2016 (ES7)

Dalam ES7, ini lebih standar, ada beberapa proposal sekarang tetapi semuanya dapat Anda lakukan await janji. Ini hanyalah "gula" (sintaks yang lebih bagus) untuk proposal ES6 di atas dengan menambahkan async dan await kata kunci. Membuat contoh di atas:

async function foo(){
    var data = await fetch("/echo/json"); // notice the await
    // code here only executes _after_ the request is done
    return data.json(); // data is defined
}

Itu masih mengembalikan janji sama saja :)


243
2018-05-12 02:22



Anda menggunakan Ajax dengan tidak benar. Idenya adalah untuk tidak mengembalikan apa-apa, tetapi menyerahkan data ke sesuatu yang disebut fungsi callback, yang menangani data.

Itu adalah:

function handleData( responseData ) {

    // Do what you want with the data
    console.log(responseData);
}

$.ajax({
    url: "hi.php",
    ...
    success: function ( data, status, XHR ) {
        handleData(data);
    }
});

Mengembalikan apa pun di dalam menyerahkan handler tidak akan melakukan apa-apa. Anda harus baik menyerahkan data, atau melakukan apa yang Anda inginkan dengannya langsung di dalam fungsi sukses.


192
2018-05-23 02:05



Solusi paling sederhana adalah membuat fungsi JavaScript dan memanggilnya untuk Ajax success panggilan balik.

function callServerAsync(){
    $.ajax({
        url: '...',
        success: function(response) {

            successCallback(response);
        }
    });
}

function successCallback(responseObj){
    // Do something like read the response and show data
    alert(JSON.stringify(responseObj)); // Only applicable to JSON response
}

function foo(callback) {

    $.ajax({
        url: '...',
        success: function(response) {
           return callback(null, response);
        }
    });
}

var result = foo(function(err, result){
          if (!err)
           console.log(result);    
}); 

184
2018-02-18 18:58



Saya akan menjawab dengan komik yang tampak mengerikan dan digambar tangan. Citra kedua adalah alasan mengapa result aku s undefined dalam contoh kode Anda.

enter image description here


154
2017-08-11 14:17



Angular1

Untuk orang yang menggunakan AngularJS, dapat menangani situasi ini menggunakan Promises.

Sini ia mengatakan,

Janji dapat digunakan untuk fungsi asynchronous yang tidak perlu dan memungkinkan seseorang untuk menggabungkan beberapa fungsi bersama-sama.

Anda dapat menemukan penjelasan yang bagus sini juga.

Contoh yang ditemukan di dokumen disebutkan di bawah.

  promiseB = promiseA.then(
    function onSuccess(result) {
      return result + 1;
    }
    ,function onError(err) {
      //Handle error
    }
  );

 // promiseB will be resolved immediately after promiseA is resolved 
 // and its value will be the result of promiseA incremented by 1.

Angular2 dan Nanti

Di Angular2 dengan melihat contoh berikut, tetapi direkomendasikan menggunakan Observables dengan Angular2.

 search(term: string) {
     return this.http
  .get(`https://api.spotify.com/v1/search?q=${term}&type=artist`)
  .map((response) => response.json())
  .toPromise();

}

Anda dapat mengkonsumsi itu dengan cara ini,

search() {
    this.searchService.search(this.searchField.value)
      .then((result) => {
    this.result = result.artists.items;
  })
  .catch((error) => console.error(error));
}

Lihat asli posting di sini. Tetapi Typescript tidak mendukung Janji es6 asli, jika Anda ingin menggunakannya, Anda mungkin memerlukan plugin untuk itu.

Selain itu di sini adalah janji-janji spesifikasi definisikan di sini.


113
2017-08-26 08:11



Sebagian besar jawaban di sini memberikan saran yang berguna ketika Anda memiliki operasi async tunggal, tetapi kadang-kadang, ini muncul ketika Anda perlu melakukan operasi asynchronous untuk setiap masuk dalam larik atau struktur lain yang seperti daftar. Godaannya adalah melakukan ini:

// WRONG
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log(results); // E.g., using them, returning them, etc.

Contoh:

// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log("Results:", results); // E.g., using them, returning them, etc.

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

Alasan yang tidak berfungsi adalah callback dari doSomethingAsync belum berjalan saat Anda mencoba menggunakan hasilnya.

Jadi, jika Anda memiliki array (atau daftar sejenis) dan ingin melakukan operasi async untuk setiap entri, Anda memiliki dua opsi: Lakukan operasi secara paralel (tumpang tindih), atau secara seri (satu demi satu secara berurutan).

Paralel

Anda dapat memulai semuanya dan melacak berapa banyak callback yang Anda harapkan, dan kemudian menggunakan hasilnya ketika Anda mendapatkan banyak callback:

var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

Contoh:

var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Kita bisa melakukannya expecting dan hanya digunakan results.length === theArray.length, tapi itu membuat kita terbuka untuk kemungkinan itu theArray berubah saat panggilan luar biasa ...)

Perhatikan bagaimana kami menggunakan index dari forEach untuk menyimpan hasilnya results dalam posisi yang sama dengan entri yang terkait, bahkan jika hasilnya tiba tidak berurutan (karena panggilan async tidak perlu diselesaikan sesuai urutan dimulainya).

Tetapi bagaimana jika Anda perlu kembali hasil-hasil dari suatu fungsi? Seperti yang telah ditunjukkan oleh jawaban lainnya, Anda tidak bisa; Anda harus memiliki fungsi Anda menerima dan memanggil callback (atau mengembalikan a Janji). Berikut ini adalah versi panggilan balik:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

Contoh:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

Atau inilah versi yang mengembalikan a Promise sebagai gantinya:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Tentu saja jika doSomethingAsync menyampaikan kesalahan kepada kami, kami akan menggunakan reject untuk menolak janji ketika kami mendapat kesalahan.)

Contoh:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Atau secara bergantian, Anda bisa membuat pembungkus untuk doSomethingAsync yang mengembalikan janji, dan kemudian lakukan di bawah ...)

Jika doSomethingAsync memberi Anda Janji, Kamu dapat memakai Promise.all:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Contoh:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

Perhatikan itu Promise.all menyelesaikan janjinya dengan berbagai hasil dari semua janji yang Anda berikan ketika semuanya telah diselesaikan, atau menolak janjinya ketika pertama dari janji-janji yang Anda berikan itu ditolak.

Seri

Misalkan Anda tidak ingin operasi menjadi paralel? Jika Anda ingin menjalankannya satu demi satu, Anda harus menunggu setiap operasi selesai sebelum Anda memulai berikutnya. Berikut ini contoh fungsi yang melakukan itu dan memanggil callback dengan hasilnya:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

(Karena kita melakukan pekerjaan secara seri, kita bisa menggunakannya results.push(result) karena kami tahu kami tidak akan mendapatkan hasil dari pesanan. Di atas, kita bisa menggunakannya results[index] = result;, tetapi dalam beberapa contoh berikut ini kami tidak memiliki indeks untuk digunakan.)

Contoh:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Atau, lagi, buat pembungkus untuk doSomethingAsync yang memberi Anda janji dan lakukan yang berikut ...)

Jika doSomethingAsync memberi Anda sebuah Janji, jika Anda dapat menggunakan sintaks ES2017 + (mungkin dengan transpiler seperti Babel), Anda dapat menggunakan async fungsi dengan for-of dan await:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

Contoh:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

Jika Anda tidak dapat menggunakan ES2017 + sintaks (belum), Anda dapat menggunakan variasi pada "Janji mengurangi" pola (ini lebih kompleks daripada Janji yang biasa dikurangi karena kita tidak memberikan hasil dari satu ke yang berikutnya, tetapi mengumpulkan hasil mereka dalam sebuah array):

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Contoh:

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

... yang kurang praktis ES2015 + fungsi panah:

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

Contoh:

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}


90
2018-05-03 16:59



Lihatlah contoh ini:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope,$http) {

    var getJoke = function(){
        return $http.get('http://api.icndb.com/jokes/random').then(function(res){
            return res.data.value;  
        });
    }

    getJoke().then(function(res) {
        console.log(res.joke);
    });
});

Seperti yang Anda lihat getJoke aku s mengembalikan a terselesaikan janji (ini diselesaikan saat kembali res.data.value). Jadi Anda tunggu sampai $ http.get permintaan selesai dan kemudian console.log (res.joke) dijalankan (sebagai aliran asynchronous normal).

Ini adalah plnkr:

http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/


73
2018-06-02 08:31



Pendekatan lain untuk mengembalikan nilai dari fungsi asynchronous, adalah dengan mengirimkan objek yang akan menyimpan hasil dari fungsi asynchronous.

Berikut ini contoh yang sama:

var async = require("async");

// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
    // some asynchronous operation
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;
            _callback();
        }
    });
});

async.parallel(asyncTasks, function(){
    // result is available after performing asynchronous operation
    console.log(result)
    console.log('Done');
});

Saya menggunakan result objek untuk menyimpan nilai selama operasi asynchronous. Ini memungkinkan hasil tersedia bahkan setelah pekerjaan asynchronous.

Saya menggunakan pendekatan ini banyak. Saya akan tertarik untuk mengetahui seberapa baik pendekatan ini bekerja di mana pengkabelan hasil kembali melalui modul berturut-turut dilibatkan.


69
2017-09-02 12:54