Pertama, ini adalah kasus yang sangat spesifik untuk melakukannya dengan cara yang salah dengan sengaja untuk retrofit panggilan asinkron ke basis kode yang sangat sinkron yang ribuan baris panjang dan waktu saat ini tidak mampu melakukan perubahan untuk "melakukan itu benar." Itu menyakiti setiap serat dari keberadaan saya, tetapi kenyataan dan cita-cita sering tidak sesuai. Saya tahu ini menyebalkan.
OK, itu keluar dari jalan, bagaimana cara membuatnya sehingga saya bisa:
function doSomething() {
var data;
function callBack(d) {
data = d;
}
myAsynchronousCall(param1, callBack);
// block here and return data when the callback is finished
return data;
}
Contoh-contoh (atau ketiadaan) semuanya menggunakan pustaka dan / atau kompiler, yang keduanya tidak layak untuk solusi ini. Saya perlu contoh konkret tentang cara membuatnya blok (misalnya TIDAK meninggalkan fungsi doSomething sampai panggilan balik dipanggil) TANPA membekukan UI. Jika hal seperti itu dimungkinkan di JS.
sumber
Jawaban:
BAIK. tetapi Anda harus benar-benar melakukannya dengan cara yang benar ... atau apa pun
Tidak, tidak mungkin untuk memblokir JavaScript yang berjalan tanpa memblokir UI.
Mengingat kurangnya informasi, sulit untuk menawarkan solusi, tetapi salah satu opsi mungkin memiliki fungsi panggilan melakukan beberapa polling untuk memeriksa variabel global, kemudian mengatur callback
data
ke global.Semua ini mengasumsikan bahwa Anda dapat memodifikasi
doSomething()
. Saya tidak tahu apakah itu ada dalam kartu.Jika itu dapat dimodifikasi, maka saya tidak tahu mengapa Anda tidak hanya meneruskan panggilan balik untuk
doSomething()
dipanggil dari panggilan balik lain, tapi saya lebih baik berhenti sebelum saya mendapat masalah. ;)Oh, apa-apaan ini. Anda memberi contoh yang menunjukkan itu bisa dilakukan dengan benar, jadi saya akan menunjukkan solusi itu ...
Karena contoh Anda menyertakan panggilan balik yang diteruskan ke panggilan async, cara yang benar adalah dengan melewatkan fungsi yang
doSomething()
akan dipanggil dari panggilan balik.Tentu saja jika itu satu-satunya hal yang dilakukan callback, Anda hanya akan lulus
func
langsung ...sumber
callback
fungsi kemyAsynchronousCall
fungsi, yang melakukan hal-hal async dan memanggil kembali ketika selesai. Ini demo.Fungsi Async , fitur di ES2017 , membuat sinkronisasi kode async dengan menggunakan janji (bentuk tertentu dari kode async) dan
await
kata kunci. Perhatikan juga dalam contoh kode di bawah kata kunciasync
di depanfunction
kata kunci yang menandakan fungsi async / menunggu. Kataawait
kunci tidak akan berfungsi tanpa berada dalam fungsi yang telah diperbaiki sebelumnya denganasync
kata kunci. Karena saat ini tidak ada pengecualian untuk ini yang berarti tidak ada level atas yang menunggu akan berfungsi (level atas menunggu artinya menunggu di luar fungsi apa pun). Padahal ada proposal untuk level atasawait
.ES2017 telah disahkan (yaitu difinalisasi) sebagai standar untuk JavaScript pada 27 Juni 2017. Async menunggu mungkin sudah berfungsi di browser Anda, tetapi jika tidak Anda masih dapat menggunakan fungsionalitas menggunakan javascript transpiler seperti babel atau traceur . Chrome 55 mendapat dukungan penuh dari fungsi-fungsi async. Jadi, jika Anda memiliki peramban yang lebih baru, Anda mungkin dapat mencoba kode di bawah ini.
Lihat tabel kompatibilitas es2017 kangax untuk kompatibilitas peramban.
Berikut ini contoh fungsi menunggu async
doAsync
yang dipanggil yang mengambil tiga satu jeda detik dan mencetak perbedaan waktu setelah setiap jeda dari waktu mulai:Ketika kata kunci yang menunggu ditempatkan sebelum nilai janji (dalam hal ini nilai janji adalah nilai yang dikembalikan oleh fungsi doSomethingAsync) kata kunci yang menunggu akan menjeda pelaksanaan panggilan fungsi, tetapi tidak akan menghentikan sementara fungsi lain dan itu akan melanjutkan mengeksekusi kode lain sampai janji terselesaikan. Setelah janji terselesaikan, itu akan membuka nilai janji dan Anda dapat memikirkan ekspresi menunggu dan janji yang sekarang sedang digantikan oleh nilai yang terbuka.
Jadi, karena menunggu hanya jeda menunggu kemudian membuka nilai sebelum mengeksekusi sisa baris Anda dapat menggunakannya dalam untuk loop dan panggilan fungsi di dalam seperti dalam contoh di bawah ini yang mengumpulkan perbedaan waktu yang ditunggu dalam array dan mencetak array.
Fungsi async sendiri mengembalikan janji sehingga Anda dapat menggunakannya sebagai janji dengan rantai seperti yang saya lakukan di atas atau di dalam fungsi menunggu async lainnya.
Fungsi di atas akan menunggu setiap respons sebelum mengirim permintaan lain jika Anda ingin mengirim permintaan secara bersamaan, Anda dapat menggunakan Promise.all .
Jika janji itu mungkin ditolak, Anda dapat membungkusnya dengan try catch atau melewati try catch dan membiarkan kesalahan tersebut menyebar ke fungsi async / await catch call. Anda harus berhati-hati untuk tidak meninggalkan kesalahan janji tidak tertangani terutama di Node.js. Di bawah ini adalah beberapa contoh yang menunjukkan bagaimana kesalahan bekerja.
Jika Anda pergi ke sini, Anda dapat melihat proposal yang sudah jadi untuk versi ECMAScript mendatang.
Alternatif untuk ini yang dapat digunakan hanya dengan ES2015 (ES6) adalah dengan menggunakan fungsi khusus yang membungkus fungsi generator. Fungsi generator memiliki kata kunci hasil yang dapat digunakan untuk mereplikasi kata kunci yang menunggu dengan fungsi sekitarnya. Fungsi kata kunci dan generator hasil adalah tujuan yang jauh lebih umum dan dapat melakukan banyak hal lebih banyak daripada apa fungsi fungsi async menunggu. Jika Anda ingin pembungkus fungsi generator yang dapat digunakan untuk mereplikasi async, saya akan menunggu co.js . Ngomong-ngomong fungsi co sama seperti async menunggu fungsi mengembalikan janji. Jujur meskipun pada titik ini kompatibilitas browser hampir sama untuk fungsi generator dan fungsi async jadi jika Anda hanya ingin fungsi menunggu async Anda harus menggunakan fungsi Async tanpa co.js.
Dukungan browser sebenarnya cukup bagus sekarang untuk fungsi Async (pada 2017) di semua browser utama saat ini (Chrome, Safari, dan Edge) kecuali IE.
sumber
Lihatlah JQuery Promises:
http://api.jquery.com/promise/
http://api.jquery.com/jQuery.when/
http://api.jquery.com/deferred.promise/
Perbaiki kode:
sumber
dfd.notify(data)
untukdfd.resolve(data)
Ada satu solusi yang bagus di http://taskjs.org/
Menggunakan generator yang baru mengenal javascript. Jadi saat ini tidak diterapkan oleh sebagian besar browser. Saya mengujinya di firefox, dan bagi saya itu cara yang bagus untuk membungkus fungsi asinkron.
Berikut ini contoh kode dari proyek GitHub
sumber
Anda dapat memaksa JavaScript asinkron di NodeJS agar sinkron dengan sync-rpc .
Ini pasti akan membekukan UI Anda, jadi saya masih tidak yakin ketika menyangkut apakah mungkin untuk mengambil jalan pintas yang perlu Anda ambil. Tidak mungkin untuk menangguhkan Utas Satu-Satunya dalam JavaScript, bahkan jika NodeJS memungkinkan Anda memblokirnya terkadang. Tidak ada panggilan balik, acara, apa pun yang tidak sinkron sama sekali akan dapat diproses sampai janji Anda terselesaikan. Jadi kecuali Anda pembaca memiliki situasi yang tidak dapat dihindari seperti OP (atau, dalam kasus saya, sedang menulis skrip shell yang dimuliakan tanpa callback, acara, dll.), JANGAN LAKUKAN INI!
Tapi begini caranya Anda bisa melakukan ini:
./calling-file.js
./my-asynchronous-call.js
BATASAN:
Ini adalah konsekuensi dari cara
sync-rpc
penerapannya, yaitu dengan menyalahgunakanrequire('child_process').spawnSync
:JSON.stringify
, sehingga fungsi dan properti yang tidak dapat dihitung seperti rantai prototipe akan hilang.sumber
Anda juga dapat mengubahnya menjadi panggilan balik.
sumber
Yang Anda inginkan sebenarnya mungkin sekarang. Jika Anda dapat menjalankan kode asinkron di pekerja layanan, dan kode sinkron di pekerja web, maka Anda dapat meminta pekerja web mengirim XHR sinkron ke pekerja layanan, dan sementara pekerja layanan melakukan hal-hal async, pekerja web utas akan menunggu. Ini bukan pendekatan yang bagus, tetapi bisa berhasil.
sumber
Gagasan yang ingin Anda capai dapat dimungkinkan jika Anda mengubah sedikit persyaratan
Kode di bawah ini dimungkinkan jika runtime Anda mendukung spesifikasi ES6.
Lebih lanjut tentang fungsi async
sumber
SyntaxError: await is only valid in async functions and async generators
. Belum lagi param1 yang tidak didefinisikan (dan bahkan tidak digunakan).