Saya ingin membuat halaman yang menampilkan beberapa data dari DB, jadi saya telah membuat beberapa fungsi yang mendapatkan data dari DB saya. Saya hanya seorang pemula di Node.js, sejauh yang saya mengerti, jika saya ingin menggunakan semuanya dalam satu halaman (respon HTTP), saya harus membuat semuanya:
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
getSomeDate(client, function(someData) {
html += "<p>"+ someData +"</p>";
getSomeOtherDate(client, function(someOtherData) {
html += "<p>"+ someOtherData +"</p>";
getMoreData(client, function(moreData) {
html += "<p>"+ moreData +"</p>";
res.write(html);
res.end();
});
});
});
Jika ada banyak fungsi seperti itu, maka persarangan menjadi masalah .
Apakah ada cara untuk menghindari ini? Saya kira itu ada hubungannya dengan bagaimana Anda menggabungkan beberapa fungsi asinkron, yang tampaknya menjadi sesuatu yang mendasar.
getSomeDate
dangetSomeOtherDate
berakhir dengan mengubah lekukan banyak baris yang membuat sejarah git lebih sulit dibaca (git blame
bahkan tidak berguna setelah ini), dan Anda mungkin membuat bug saat melakukan ini secara manualJawaban:
Pengamatan menarik. Perhatikan bahwa dalam JavaScript Anda biasanya dapat mengganti fungsi panggilan balik anonim sebaris dengan variabel fungsi bernama.
Pengikut:
Dapat ditulis ulang agar terlihat seperti ini:
Namun, kecuali jika Anda berencana untuk menggunakan kembali logika panggilan balik di tempat lain, seringkali lebih mudah untuk membaca fungsi anonim sebaris, seperti pada contoh Anda. Ini juga akan menghindarkan Anda dari keharusan mencari nama untuk semua panggilan balik.
Sebagai tambahan perhatikan bahwa seperti @pst dicatat dalam komentar di bawah, jika Anda mengakses variabel penutupan dalam fungsi-fungsi dalam, di atas tidak akan menjadi terjemahan langsung. Dalam kasus seperti itu, menggunakan fungsi anonim sebaris bahkan lebih disukai.
sumber
getMoreData
hilang.someDataParser
sebenarnya mem-parsing SEMUA data, karena itu juga memanggilgetMoreData
. Dalam pengertian itu, nama fungsi salah dan menjadi jelas bahwa kita belum benar-benar menghapus masalah bersarang.Kay, cukup gunakan salah satu modul ini.
Ini akan mengubah ini:
Ke dalam ini:
sumber
Sebagian besar, saya setuju dengan Daniel Vassallo. Jika Anda dapat memecah fungsi yang rumit dan bersarang menjadi fungsi bernama terpisah, maka itu biasanya ide yang baik. Untuk saat-saat ketika masuk akal untuk melakukannya di dalam satu fungsi, Anda dapat menggunakan salah satu dari banyak pustaka async node.js yang tersedia. Orang-orang telah menemukan banyak cara berbeda untuk mengatasi hal ini, jadi lihat halaman modul node.js dan lihat apa yang Anda pikirkan.
Saya telah menulis modul untuk ini sendiri, bernama async.js . Dengan menggunakan ini, contoh di atas dapat diperbarui ke:
Satu hal yang menyenangkan tentang pendekatan ini adalah Anda dapat dengan cepat mengubah kode Anda untuk mengambil data secara paralel dengan mengubah fungsi 'seri' menjadi 'paralel'. Terlebih lagi, async.js juga akan berfungsi di dalam browser, sehingga Anda dapat menggunakan metode yang sama seperti di node.js jika Anda menemukan kode async yang rumit.
Semoga bermanfaat!
sumber
Anda bisa menggunakan trik ini dengan array daripada fungsi bersarang atau modul.
Jauh lebih mudah di mata.
Anda dapat memperluas idiom untuk proses paralel atau bahkan rantai proses paralel:
sumber
Saya suka async.js banyak untuk tujuan ini.
Masalah ini diselesaikan dengan perintah air terjun:
Contoh
Adapun req, variabel res, mereka akan dibagi dalam lingkup yang sama dengan fungsi (req, res) {} yang melampirkan seluruh panggilan async.waterfall.
Tidak hanya itu, async juga sangat bersih. Maksud saya adalah saya mengubah banyak kasus seperti ini:
Untuk pertama:
Kemudian untuk ini:
Kemudian untuk ini:
Ini juga memungkinkan banyak fungsi premade yang disiapkan untuk async dipanggil dari util.js dengan sangat cepat. Hanya rantai apa yang ingin Anda lakukan, pastikan o, cb ditangani secara universal. Ini mempercepat seluruh proses pengkodean.
sumber
Yang Anda butuhkan adalah sedikit gula sintaksis. Hapus ini:
Cukup rapi , bukan? Anda mungkin memperhatikan bahwa html menjadi sebuah array. Itu sebagian karena string tidak dapat diubah, jadi Anda lebih baik dengan buffering output Anda dalam array, daripada membuang string yang lebih besar dan lebih besar. Alasan lainnya adalah karena sintaks yang bagus dengan
bind
.Queue
dalam contoh tersebut benar-benar hanya sebuah contoh dan bersamaan dengan itupartial
dapat diimplementasikan sebagai berikutsumber
last
fungsi opsional )obj.email
dan fungsi Anda berikutnya menggunakanobj.email
lalu menghapusnya (atau hanya menetapkannull
).Aku jatuh cinta pada Async.js sejak aku menemukannya. Ini memiliki
async.series
fungsi yang dapat Anda gunakan untuk menghindari lama bersarang.Dokumentasi:-
seri (tugas, [panggilan balik])
Jalankan berbagai fungsi secara seri, masing-masing berjalan setelah fungsi sebelumnya selesai. [...]
Argumen
tasks
- Berbagai fungsi untuk dijalankan, setiap fungsi dilewati panggilan balik yang harus dipanggil saat selesai.callback(err, [results])
- Callback opsional untuk dijalankan setelah semua fungsi selesai. Fungsi ini mendapatkan array dari semua argumen yang diteruskan ke panggilan balik yang digunakan dalam array.Begini cara kami menerapkannya pada kode contoh Anda: -
sumber
Gula sintaksis paling sederhana yang saya lihat adalah simpul-janji.
npm instal simpul-janji || git clone https://github.com/kriszyp/node-promise
Dengan ini, Anda dapat menggunakan metode async sebagai:
Nilai kembali dari masing-masing tersedia sebagai argumen di berikutnya.
sumber
Apa yang telah Anda lakukan di sana adalah mengambil pola asynch dan menerapkannya pada 3 fungsi yang disebut secara berurutan, masing-masing menunggu yang sebelumnya selesai sebelum mulai - yaitu Anda telah membuatnya sinkron . Intinya tentang pemrograman asynch adalah Anda dapat memiliki beberapa fungsi yang semuanya berjalan sekaligus dan tidak harus menunggu masing-masing untuk menyelesaikan.
jika getSomeDate () tidak menyediakan apa pun untuk getSomeOtherDate (), yang tidak menyediakan apa pun untuk getMoreData () lalu mengapa Anda tidak memanggilnya secara asinkron sesuai js memungkinkan atau jika mereka saling bergantung (dan tidak asinkron) tuliskan mereka sebagai fungsi tunggal?
Anda tidak perlu menggunakan sarang untuk mengontrol aliran - misalnya, dapatkan setiap fungsi selesai dengan memanggil fungsi umum yang menentukan kapan ketiganya telah selesai dan kemudian mengirim respons.
sumber
Misalkan Anda bisa melakukan ini:
Anda hanya perlu mengimplementasikan rantai () sehingga sebagian menerapkan setiap fungsi ke yang berikutnya, dan segera memanggil hanya fungsi pertama:
sumber
panggilan balik neraka dapat dengan mudah dihindari dalam javascript murni dengan penutupan. solusi di bawah ini mengasumsikan semua panggilan balik mengikuti tanda tangan fungsi (kesalahan, data).
sumber
Saya baru-baru ini membuat abstraksi sederhana bernama wait.for untuk memanggil fungsi async dalam mode sinkronisasi (berdasarkan Serat). Ini pada tahap awal tetapi berhasil. Ini di:
https://github.com/luciotato/waitfor
Menggunakan wait.for , Anda dapat memanggil fungsi async nodejs standar apa saja, seolah-olah itu adalah fungsi sinkronisasi.
menggunakan wait.for kode Anda bisa:
... atau jika Anda ingin kurang verbose (dan juga menambahkan kesalahan menangkap)
Dalam semua kasus, getSomeDate , getSomeOtherDate dan getMoreData harus menjadi fungsi async standar dengan parameter terakhir berupa fungsi callback (err, data)
seperti dalam:
sumber
Untuk mengatasi masalah ini saya menulis anggukan ( https://npmjs.org/package/nodent ) yang secara tak terlihat memproses pra-JS Anda. Kode contoh Anda akan menjadi (async, really - read the docs).
Jelas, ada banyak solusi lain, tetapi pra-pemrosesan memiliki keuntungan memiliki sedikit overhead atau tidak ada run-time dan berkat dukungan sumber-peta juga mudah untuk debug.
sumber
Saya memiliki masalah yang sama. Saya telah melihat libs utama untuk menjalankan fungsi async node, dan mereka menyajikan chaining begitu tidak alami (Anda perlu menggunakan tiga atau lebih metode confs dll) untuk membangun kode Anda.
Saya menghabiskan beberapa minggu mengembangkan solusi untuk menjadi sederhana dan mudah dibaca. Tolong, coba untuk EnqJS . Semua pendapat akan dihargai.
Dari pada:
dengan EnqJS:
Perhatikan bahwa kode tersebut tampak lebih besar dari sebelumnya. Tapi itu tidak bersarang seperti sebelumnya. Agar tampak lebih alami, rantai disebut segera:
Dan untuk mengatakan bahwa itu kembali, di dalam fungsi yang kami sebut:
sumber
Saya melakukannya dengan cara yang cukup primitif tetapi efektif. Misalnya saya perlu mendapatkan model dengan orang tua dan anak-anak dan katakanlah saya perlu melakukan pertanyaan terpisah untuk mereka:
sumber
Gunakan Serat https://github.com/laverdet/node-fibers membuat kode asinkron terlihat seperti sinkron (tanpa pemblokiran)
Saya pribadi menggunakan sedikit pembungkus http://alexeypetrushin.github.com/synchronize Contoh kode dari proyek saya (setiap metode sebenarnya asynchronous, bekerja dengan file yang async IO) Aku bahkan takut membayangkan apa berantakan itu akan dengan callback atau perpustakaan pembantu async-control-flow.
sumber
Task.js menawarkan ini kepada Anda:
Alih-alih ini:
sumber
Setelah yang lain merespons, Anda menyatakan bahwa masalah Anda adalah variabel lokal. Tampaknya cara yang mudah untuk melakukan ini adalah menulis satu fungsi luar untuk memuat variabel-variabel lokal, kemudian menggunakan sekelompok fungsi dalam bernama dan mengaksesnya dengan nama. Dengan cara ini, Anda hanya akan memiliki dua sarang, terlepas dari berapa banyak fungsi yang Anda butuhkan untuk rantai bersama.
Ini adalah usaha pemula saya untuk menggunakan
mysql
modul Node.js dengan nesting:Berikut ini adalah penulisan ulang menggunakan fungsi dalam bernama. Fungsi luar
with_connection
juga dapat digunakan sebagai penahan untuk variabel lokal. (Di sini, saya punya parametersql
,bindings
,cb
yang bertindak dengan cara yang sama, tetapi Anda hanya dapat mendefinisikan beberapa variabel lokal tambahan diwith_connection
.)Saya telah berpikir bahwa mungkin akan mungkin untuk membuat objek dengan variabel instan, dan menggunakan variabel instan ini sebagai pengganti variabel lokal. Tapi sekarang saya menemukan bahwa pendekatan di atas menggunakan fungsi bersarang dan variabel lokal lebih sederhana dan lebih mudah dipahami. Butuh waktu untuk menghapus OO, sepertinya :-)
Jadi di sini adalah versi saya sebelumnya dengan variabel objek dan instance.
Ternyata itu
bind
bisa digunakan untuk beberapa keuntungan. Ini memungkinkan saya untuk menyingkirkan fungsi anonim yang agak jelek yang saya buat yang tidak melakukan banyak hal, kecuali untuk meneruskan diri ke pemanggilan metode. Saya tidak bisa lulus metode secara langsung karena akan terlibat dengan nilai yang salahthis
. Tetapi denganbind
, saya dapat menentukan nilaithis
yang saya inginkan.Tentu saja, semua ini bukan JS yang sesuai dengan Node.js coding - Saya hanya menghabiskan beberapa jam untuk itu. Tapi mungkin dengan sedikit memoles teknik ini bisa membantu?
sumber
async.js bekerja dengan baik untuk ini. Saya menemukan artikel yang sangat berguna ini yang menjelaskan kebutuhan dan penggunaan async.js dengan contoh: http://www.sebastianseilund.com/nodejs-async-in-practice
sumber
Jika Anda tidak ingin menggunakan "step" atau "seq", silakan coba "line" yang merupakan fungsi sederhana untuk mengurangi callback async bersarang.
https://github.com/kevin0571/node-line
sumber
Asyncawait mirip C adalah cara lain untuk melakukan ini
https://github.com/yortus/asyncawait
sumber
Menggunakan kawat kode Anda akan terlihat seperti ini:
sumber
untuk Anda ketahui pertimbangkan Jazz.js https://github.com/Javanile/Jazz.js/wiki/Script-showcase
sumber