Saya memiliki dua fungsi JS. Yang satu memanggil yang lain. Di dalam fungsi panggilan, saya ingin memanggil yang lain, menunggu sampai fungsi itu selesai, lalu melanjutkan. Jadi, misalnya / kode semu:
function firstFunction(){
for(i=0;i<x;i++){
// do something
}
};
function secondFunction(){
firstFunction()
// now wait for firstFunction to finish...
// do something else
};
Saya datang dengan solusi ini, tetapi tidak tahu apakah ini cara yang cerdas untuk melakukannya.
var isPaused = false;
function firstFunction(){
isPaused = true;
for(i=0;i<x;i++){
// do something
}
isPaused = false;
};
function secondFunction(){
firstFunction()
function waitForIt(){
if (isPaused) {
setTimeout(function(){waitForIt()},100);
} else {
// go do that thing
};
}
};
Apakah itu sah? Apakah ada cara yang lebih elegan untuk menanganinya? Mungkin dengan jQuery?
firstFunction
sebenarnya yang membuatnya tidak sinkron? Either way - periksa tentang janjiJawaban:
Salah satu cara untuk menangani pekerjaan asinkron seperti ini adalah dengan menggunakan fungsi panggilan balik, misalnya:
Sesuai saran @Janaka Pushpakumara, Anda sekarang dapat menggunakan fungsi panah untuk mencapai hal yang sama. Sebagai contoh:
firstFunction(() => console.log('huzzah, I\'m done!'))
Pembaruan: Saya menjawab ini beberapa waktu yang lalu, dan benar-benar ingin memperbaruinya. Sementara panggilan balik benar-benar baik-baik saja, dalam pengalaman saya mereka cenderung menghasilkan kode yang lebih sulit dibaca dan dipelihara. Ada situasi di mana saya masih menggunakannya, seperti untuk meneruskan dalam acara kemajuan dan sejenisnya sebagai parameter. Pembaruan ini hanya untuk menekankan alternatif.
Juga pertanyaan aslinya tidak secara spesifik menyebutkan async, jadi kalau-kalau ada yang bingung, jika fungsi Anda sinkron, itu akan diblokir ketika dipanggil. Sebagai contoh:
Jika meskipun tersirat, fungsinya asinkron, cara saya cenderung menangani semua pekerjaan asinkron saya hari ini adalah dengan async / menunggu. Sebagai contoh:
IMO, async / menunggu membuat kode Anda jauh lebih mudah dibaca daripada menggunakan janji secara langsung (sebagian besar waktu). Jika Anda perlu menangani kesalahan penangkapan maka gunakan dengan mencoba / menangkap. Baca lebih lanjut di sini: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function .
sumber
Gunakan async / tunggu:
lalu gunakan menunggu di fungsi Anda yang lain untuk menunggu kembali:
sumber
$(function() { await firstFunction(); secondFunction(); });
,?await
hanya dapat digunakan di dalam suatuasync
metode. Jadi, jika Anda membuat fungsi orang tua,async
Anda dapat memanggil sebanyak mungkin orangasync methods
di dalam dengan atau tanpaawait
yang Anda inginkan.await
suatusetTimeout
?Tampaknya Anda melewatkan satu poin penting di sini: JavaScript adalah lingkungan eksekusi berulir tunggal. Mari kita lihat kembali kode Anda, perhatikan saya telah menambahkan
alert("Here")
:Anda tidak harus menunggu
isPaused
. Ketika Anda melihat peringatan "Di Sini",isPaused
akanfalse
sudah, danfirstFunction
akan kembali. Itu karena Anda tidak dapat "menghasilkan" dari dalamfor
loop (// do something
), loop mungkin tidak terputus dan harus sepenuhnya menyelesaikan terlebih dahulu (lebih detail: Javascript thread-handling dan ras-conditions ).Yang mengatakan, Anda masih dapat membuat aliran kode di dalam
firstFunction
menjadi asinkron dan menggunakan panggilan balik atau janji untuk memberi tahu penelepon. Anda harus menyerah padafor
loop dan mensimulasikannya sebagaiif
gantinya ( JSFiddle ):Sebagai tambahan, JavaScript 1.7 telah memperkenalkan
yield
kata kunci sebagai bagian dari generator . Itu akan memungkinkan untuk "meninju" lubang asinkron dalam aliran kode JavaScript yang sebaliknya sinkron ( lebih detail dan contoh ). Namun, dukungan browser untuk generator saat ini terbatas untuk Firefox dan Chrome, AFAIK.sumber
Cara elegan untuk menunggu satu fungsi selesai terlebih dahulu adalah menggunakan Janji dengan fungsi async / menunggu .
setTimeout
untuk menunjukkan situasi di mana instruksi akan memakan waktu untuk dieksekusi.await
menyelesaikan fungsi pertama sebelum melanjutkan dengan instruksi.Contoh:
catatan:
Anda hanya bisa
resolve
yangPromise
tanpa nilai apapun seperti begituresolve()
. Dalam contoh saya, sayaresolved
yangPromise
dengan nilaiy
yang saya kemudian dapat digunakan dalam fungsi kedua.sumber
Satu-satunya masalah dengan janji adalah bahwa IE tidak mendukungnya. Edge melakukannya, tetapi ada banyak IE 10 dan 11 di luar sana: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise (kompatibilitas di bagian bawah)
Jadi, JavaScript adalah utas tunggal. Jika Anda tidak melakukan panggilan asinkron, itu akan berperilaku terprediksi. Utas JavaScript utama akan menjalankan satu fungsi sepenuhnya sebelum menjalankan yang berikutnya, sesuai urutan yang muncul dalam kode. Jaminan pesanan untuk fungsi sinkron adalah sepele - setiap fungsi akan dieksekusi sepenuhnya dalam urutan yang dipanggil.
Pikirkan fungsi sinkron sebagai unit kerja atom . Utas JavaScript utama akan menjalankannya sepenuhnya, sesuai dengan urutan pernyataan yang muncul dalam kode.
Tapi, serahkan panggilan asinkron, seperti dalam situasi berikut:
Ini tidak melakukan apa yang Anda inginkan . Ini secara instan mengeksekusi fungsi 1, fungsi 2, dan fungsi 3. Memuat div berkedip dan hilang, sementara panggilan ajax hampir tidak lengkap, meskipun
makeAjaxCall()
telah kembali. KOMPLIKASI yangmakeAjaxCall()
telah memecah pekerjaannya menjadi potongan-potongan yang maju sedikit demi sedikit oleh setiap putaran utas JavaScript utama - itu berperilaku asikronik. Tetapi utas utama yang sama, selama satu putaran / putaran, mengeksekusi bagian sinkron dengan cepat dan dapat diprediksi.Jadi, cara saya menanganinya : Seperti saya katakan fungsinya adalah unit atom. Saya menggabungkan kode fungsi 1 dan 2 - saya meletakkan kode fungsi 1 di fungsi 2, sebelum panggilan asynch. Saya menyingkirkan fungsi 1. Semuanya hingga dan termasuk panggilan asinkron dijalankan secara terprediksi, secara berurutan.
LALU, ketika panggilan asinkron selesai, setelah beberapa putaran utas JavaScript utama, memilikinya fungsi panggil 3. Ini menjamin pesanan . Misalnya, dengan ajax, pengendali event onreadystatechange disebut beberapa kali. Ketika melaporkannya selesai, maka panggil fungsi akhir yang Anda inginkan.
Saya setuju itu berantakan. Saya suka memiliki kode menjadi simetris, saya suka memiliki fungsi melakukan satu hal (atau dekat dengan itu), dan saya tidak suka memiliki panggilan ajax dengan cara apa pun bertanggung jawab atas tampilan (membuat ketergantungan pada penelepon). NAMUN, dengan panggilan asinkron yang tertanam dalam fungsi sinkron, kompromi harus dilakukan untuk menjamin urutan eksekusi. Dan saya harus kode untuk IE 10 jadi tidak ada janji.
Rangkuman : Untuk panggilan sinkron, jaminan pesanan itu sepele. Setiap fungsi dieksekusi sepenuhnya dalam urutan yang disebutnya. Untuk fungsi dengan panggilan asinkron, satu-satunya cara untuk menjamin pesanan adalah dengan memonitor ketika panggilan async selesai, dan memanggil fungsi ketiga saat kondisi itu terdeteksi.
Untuk diskusi tentang utas JavaScript, lihat: https://medium.com/@francesco_rizzi/javascript-main-thread-dissected-43c85fce7e23 dan https://developer.mozilla.org/en-US/docs/Web/JavaScript/ EventLoop
Juga, pertanyaan serupa lainnya yang berperingkat tinggi tentang hal ini: Bagaimana saya harus memanggil 3 fungsi untuk menjalankannya satu demi satu?
sumber
Ini yang saya pikirkan, karena saya perlu menjalankan beberapa operasi dalam sebuah rantai.
sumber
Kegembiraan utama Anda akan memanggil firstFun kemudian selesaikan kesenangan Anda berikutnya akan memanggil
sumber