Bagaimana saya menunggu janji untuk selesai sebelum mengembalikan variabel fungsi?

149

Saya masih berjuang dengan janji-janji, tetapi membuat beberapa kemajuan berkat komunitas di sini.

Saya memiliki fungsi JS sederhana yang menanyakan database Parse. Seharusnya mengembalikan array hasil, tetapi jelas karena sifat asinkron dari kueri (karenanya janji), fungsi mengembalikan sebelum hasil, meninggalkan saya dengan array yang tidak ditentukan.

Apa yang harus saya lakukan untuk membuat fungsi ini menunggu hasil dari janji?

Ini kode saya:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    var promise = query.find({
               success: function(results) {
               // results is an array of Parse.Object.
                             console.log(results);
                             //resultsArray = results;
                             return results;
               },

               error: function(error) {
               // error is an instance of Parse.Error.
                             console.log("Error");
               }
    });                           

}
mac_55
sumber
3
Anda mungkin juga mempertimbangkan untuk menggunakan async / menunggu. Node sekarang mendukung async / menunggu di luar kotak sejak versi 7.6
Viliam Simko

Jawaban:

66

Alih-alih mengembalikan resultsArrayAnda mengembalikan janji untuk array hasil dan kemudian thenbahwa di situs panggilan - ini memiliki manfaat tambahan dari penelepon mengetahui fungsi melakukan I / O asinkron. Penyandian konkurensi dalam JavaScript didasarkan pada hal itu - Anda mungkin ingin membaca pertanyaan ini untuk mendapatkan ide yang lebih luas:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    return query.find({});                           

}

// later
resultsByName("Some Name").then(function(results){
    // access results here by chaining to the returned promise
});

Anda dapat melihat lebih banyak contoh menggunakan janji parse dengan kueri di posting blog Parse sendiri tentang hal itu .

Benjamin Gruenbaum
sumber
dapatkah Anda memberi tahu saya apa dukungan ini? IE9 mendukung ini?
sandrina-p
Ya, tapi Parse sendiri sebagian besar sudah mati jadi ada @SandrinaPereira. Ini adalah kode cloud parse .
Benjamin Gruenbaum
1
Ah jadi ini bukan hanya javascript murni? Saya sedang mencari cara untuk melakukan ini (menunggu fungsi selesai untuk memulai yang lain) tetapi hanya dengan javascript murni ..
sandrina-p
Pertanyaannya adalah tentang kode parse, bukan janji. Janji dapat bekerja (dengan perpustakaan) di browser apa pun. Bluebird berjalan di IE6 dan netscape 7.
Benjamin Gruenbaum
1
Saya telah membaca SO selama dua hari sekarang, dan masih, tidak ada yang menyelesaikan ini. Jawaban yang diterima ini sama dengan yang lainnya. Fungsi mengembalikan Janji, bukan nilai seperti yang diminta OP. Mengapa jawaban ini ditandai sebagai diterima?
iGanja
19

Apa yang harus saya lakukan untuk membuat fungsi ini menunggu hasil dari janji?

Gunakan async/await(BUKAN Bagian dari ECMA6, tetapi tersedia untuk Chrome, Edge, Firefox dan Safari sejak akhir 2017, lihat canIuse )
MDN

    async function waitForPromise() {
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    }

Ditambahkan karena komentar: Fungsi async selalu mengembalikan Janji, dan dalam TypeScript akan terlihat seperti:

    async function waitForPromise(): Promise<string> {
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    }
Martin Meeser
sumber
4
Fungsi async masih akan mengembalikan objek janji jika dipanggil tanpa menunggu (atau dalam kode non asinkron). Periksa hasil console.log (waitForPromise ()) jika Anda tidak yakin. Pemeriksaan console.log (hasil) dalam fungsi async akan mencetak apa yang Anda harapkan, tetapi pengembalian dari fungsi async terjadi segera tanpa memblokir dan mengembalikan janji. Pemblokiran dalam javascript biasanya sangat buruk karena ini adalah aplikasi berulir tunggal dan pemblokiran akan membuat klien pub / sub pemberitahuan lainnya kelaparan yang pada dasarnya membuat seluruh aplikasi berlutut.
SRM
1
.net memiliki .wait () pada "janji" seperti kelas tugas. Apakah Javascript tidak memiliki fitur ini? Saya perlu menunggu sesuatu sebelum keluar dari alat baris perintah simpul saya yang mungkin menyalurkan outputnya ke alat lain. "menunggu" hanya berfungsi di dalam fungsi async. Berarti itu tidak bekerja di luar ruang lingkup janji.
TamusJRoyce
@SRM Saya merasa komentar Anda didasarkan pada kesalahan interpretasi sampel - ini tentang Janji "batin". Selesaikan (sebagai contoh Janji yang paling sederhana) sehingga tidak ada penelepon luar seperti yang Anda nyatakan dalam komentar Anda. Jadi saya memutuskan untuk memperbarui jawabannya.
Martin Meeser
@TamusJRoyce Tebak itu adalah pertanyaannya sendiri tetapi saya pikir di C # Anda dapat menggunakan Task.ContinueWith (Tugas), yang merupakan ide yang sama seperti yang Anda lihat dalam jawaban yang diterima (di mana disebut "kemudian ()").
Martin Meeser
Saya rasa saya mengerti sekarang. Saya dapat membungkus seluruh skrip saya dalam satu fungsi async yang sangat besar. Dan panggil fungsi itu sebagai baris terakhir dari skrip saya. Fungsi itu masih akan menjadi sedikit pelat ketel. Tetapi jauh lebih sedikit dari yang saya rasakan sebelumnya. Saya tidak terbiasa menulis fungsi di dalam fungsi. @MartinMeeser terima kasih!
TamusJRoyce
3

Anda tidak ingin membuat fungsi menunggu, karena JavaScript dimaksudkan untuk tidak memblokir. Alih-alih mengembalikan janji di akhir fungsi, maka fungsi panggilan dapat menggunakan janji untuk mendapatkan respons server.

var promise = query.find(); 
return promise; 

//Or return query.find(); 
Jejak
sumber
1
Masalah callback Anda dengan success:bit tidak aktif.
Benjamin Gruenbaum
Atau lebih baik: return query.find();.
mash
Juga ok. Saya hanya akan membiarkannya seperti ini untuk tujuan ilustrasi tetapi menambahkannya sebagai komentar.
Lacak
Saya mencoba ini tetapi hasilnya tampaknya tidak terdefinisi. resultsByName ("name"). then (function (results) {console.log ("got array" + results.count);});
mac_55
1
Terima kasih, pasti ada semacam kesalahan di dalam fungsi hasil. Ini bekerja sekarang. Saya mengubah console.log saya ke results.length dan dapat melihat bahwa ada 1 entri di array yang saya kembalikan :)
mac_55
2

Anda sebenarnya tidak menggunakan janji di sini. Parse memungkinkan Anda menggunakan callback atau janji; pilihanmu.

Untuk menggunakan janji, lakukan hal berikut:

query.find().then(function() {
    console.log("success!");
}, function() {
    console.log("error");
});

Sekarang, untuk mengeksekusi hal-hal setelah janji selesai, Anda bisa menjalankannya di dalam janji panggilan balik di dalam then()panggilan. Sejauh ini akan sama persis dengan panggilan balik biasa.

Untuk benar-benar memanfaatkan janji adalah ketika Anda memikatnya, seperti ini:

query.find().then(function() {
    console.log("success!");

    return new Parse.Query(Obj).get("sOmE_oBjEcT");
}, function() {
    console.log("error");
}).then(function() {
    console.log("success on second callback!");
}, function() {
    console.log("error on second callback");
});
mash
sumber
Jenis objek apa yang merupakan objek hasil? karena sepertinya tidak mengandung array saya
mac_55
Seharusnya array dari Parse.Object's.
mash