Rangkuman: Apakah ada beberapa pola praktik terbaik yang mapan yang dapat saya ikuti untuk menjaga kode saya tetap terbaca meskipun menggunakan kode dan panggilan balik asinkron?
Saya menggunakan perpustakaan JavaScript yang melakukan banyak hal secara tidak sinkron dan sangat bergantung pada panggilan balik. Tampaknya menulis metode "memuat A, memuat B, ..." yang sederhana menjadi cukup rumit dan sulit diikuti dengan menggunakan pola ini.
Biarkan saya memberi contoh (buat). Katakanlah saya ingin memuat banyak gambar (asinkron) dari server web jarak jauh. Di C # / async, saya akan menulis sesuatu seperti ini:
disableStartButton();
foreach (myData in myRepository) {
var result = await LoadImageAsync("http://my/server/GetImage?" + myData.Id);
if (result.Success) {
myData.Image = result.Data;
} else {
write("error loading Image " + myData.Id);
return;
}
}
write("success");
enableStartButton();
Tata letak kode mengikuti "aliran acara": Pertama, tombol mulai dinonaktifkan, kemudian gambar dimuat ( await
memastikan bahwa UI tetap responsif) dan kemudian tombol mulai diaktifkan lagi.
Dalam JavaScript, menggunakan callback, saya menemukan ini:
disableStartButton();
var count = myRepository.length;
function loadImage(i) {
if (i >= count) {
write("success");
enableStartButton();
return;
}
myData = myRepository[i];
LoadImageAsync("http://my/server/GetImage?" + myData.Id,
function(success, data) {
if (success) {
myData.Image = data;
} else {
write("error loading image " + myData.Id);
return;
}
loadImage(i+1);
}
);
}
loadImage(0);
Saya pikir kekurangannya jelas: saya harus mengolah ulang loop menjadi panggilan rekursif, kode yang seharusnya dieksekusi pada akhirnya adalah suatu tempat di tengah fungsi, kode mulai unduhan ( loadImage(0)
) ada di bagian paling bawah, dan umumnya jauh lebih sulit untuk dibaca dan diikuti. Itu jelek dan saya tidak suka itu.
Saya yakin bahwa saya bukan orang pertama yang menghadapi masalah ini, jadi pertanyaan saya adalah: Apakah ada beberapa pola praktik terbaik yang dapat saya ikuti untuk menjaga kode saya tetap terbaca meskipun menggunakan kode asinkron dan panggilan balik?
LoadImageAsync
sebenarnya adalah panggilan untukExt.Ajax.request
Sencha Touch.async.waterfall
adalah jawaban Anda.Jawaban:
Sangat tidak mungkin bahwa Anda dapat mencapai dengan tingkat kesederhanaan dan ekspresif yang sama dalam bekerja dengan panggilan balik yang dimiliki C # 5. Compiler melakukan pekerjaan dalam menulis semua boilerplate untuk Anda, dan sampai runtime js akan melakukannya, Anda masih harus melewati callback sesekali di sana-sini.
Namun, Anda mungkin tidak selalu ingin membawa panggilan balik ke tingkat kesederhanaan kode linier - melempar fungsi tidak harus jelek, ada seluruh dunia yang bekerja dengan kode semacam ini, dan mereka tetap waras tanpa
async
danawait
.Misalnya, gunakan fungsi tingkat tinggi (js saya mungkin agak berkarat):
sumber
Butuh sedikit waktu untuk memecahkan kode mengapa Anda melakukannya dengan cara ini, tapi saya pikir ini mungkin dekat dengan yang Anda inginkan?
Pertama-tama, sebanyak permintaan AJAX yang dapat dilakukan secara bersamaan, dan menunggu sampai semuanya selesai sebelum mengaktifkan tombol Start. Ini akan lebih cepat daripada menunggu berurutan, dan, saya pikir, jauh lebih mudah untuk diikuti.
EDIT : Perhatikan bahwa ini mengasumsikan Anda telah
.each()
tersedia, dan itumyRepository
adalah array. Berhati-hatilah dengan iterasi pengulangan yang Anda gunakan di sini, jika tidak tersedia - yang ini memanfaatkan properti penutupan untuk callback. Saya tidak yakin apa yang Anda miliki, karenaLoadImageAsync
tampaknya menjadi bagian dari perpustakaan khusus - Saya tidak melihat hasil di Google.sumber
.each()
tersedia, dan, sekarang setelah Anda menyebutkannya, tidak sepenuhnya diperlukan untuk melakukan pemuatan secara berurutan. Saya pasti akan mencoba solusi Anda. (Meskipun saya akan menerima jawaban vski, karena lebih dekat dengan pertanyaan asli, yang lebih umum.)Penafian: jawaban ini tidak menjawab masalah Anda secara khusus, itu adalah jawaban umum untuk pertanyaan: "Apakah ada beberapa pola praktik terbaik yang dapat saya ikuti untuk menjaga kode saya tetap terbaca meskipun menggunakan kode asinkron dan panggilan balik?"
Dari apa yang saya tahu, tidak ada pola "mapan" untuk menangani ini. Namun, saya telah melihat dua jenis metode yang digunakan untuk menghindari mimpi buruk callback bersarang.
1 / Menggunakan fungsi bernama alih-alih panggilan balik anonim
Dengan cara ini, Anda menghindari sarang dengan mengirimkan logika fungsi anonim di fungsi lain.
2 / Menggunakan perpustakaan manajemen aliran. Saya suka menggunakan Langkah , tapi itu hanya masalah preferensi. Omong-omong, itulah yang digunakan LinkedIn.
Saya menggunakan pustaka manajemen aliran ketika saya menggunakan banyak panggilan balik bersarang, karena jauh lebih mudah dibaca ketika ada banyak kode yang menggunakannya.
sumber
Sederhananya, JavaScript tidak memiliki gula sintaksis
await
.Tetapi memindahkan bagian "ujung" ke bagian bawah fungsi itu mudah; dan dengan fungsi anonim yang dijalankan secara tidak langsung, kita dapat menghindari menyatakan referensi untuk itu.
Anda juga bisa melewati bagian "end" sebagai panggilan balik sukses ke fungsi.
sumber