Saat ini, sejumlah besar operasi asinkron terlibat dalam permintaan, dan halaman aktual semakin cenderung ke aplikasi halaman tunggal. Di masa depan, Anda dapat menggunakan tulang punggung, sudut, knockout, dan kerangka kerja lainnya, tetapi masalah pemrograman asinkron adalah masalah pertama yang dihadapi. Dengan munculnya node, pemrograman asinkron telah menjadi topik yang sangat hangat. Setelah periode belajar dan berlatih, beberapa detail pemrograman asinkron dirangkum.
1. Klasifikasi pemrograman asinkron
Metode untuk menyelesaikan masalah asinkron umumnya meliputi: panggilan balik langsung, pub/sub mode (mode acara), pustaka kontrol pustaka asinkron (seperti async, when), janji, generator, dll.
1.1 Fungsi panggilan balik
Fungsi callback biasanya digunakan untuk menyelesaikan solusi asinkron, sering diekspos dan digunakan, mudah dimengerti, dan sangat mudah diimplementasikan di perpustakaan atau fungsi. Ini juga merupakan metode yang sering digunakan orang saat menggunakan pemrograman asinkron.
Namun, metode fungsi callback memiliki masalah berikut:
1. Piramida kejahatan bersarang dapat dibentuk, dan kodenya tidak mudah dibaca;
2. Hanya satu fungsi panggilan balik yang dapat sesuai, yang menjadi batas dalam banyak skenario.
1.2 Mode Pub/Sub (Event)
Pola ini juga disebut Mode Acara, yang merupakan acara dari fungsi panggilan balik dan sangat umum di perpustakaan kelas seperti jQuery.
Acara menerbitkan mode pelanggan itu sendiri tidak memiliki masalah panggilan sinkron dan asinkron, tetapi dalam node, panggilan yang dipancarkan sebagian besar dipicu secara tidak sinkron dengan loop acara. Mode ini sering digunakan untuk memisahkan logika bisnis. Penerbit acara tidak perlu memperhatikan fungsi panggilan balik yang terdaftar, juga tidak perlu memperhatikan jumlah fungsi panggilan balik. Data dapat ditransmisikan secara fleksibel melalui pesan.
Manfaat dari pola ini adalah: 1. Mudah dimengerti; 2. Tidak lagi terbatas pada satu fungsi panggilan balik.
Ketika datang ke hal -hal buruk: 1. Anda perlu menggunakan perpustakaan kelas; 2. Urutan acara dan fungsi panggilan balik sangat penting
Salinan kode adalah sebagai berikut:
var img = document.queryselect (#ID);
img.addeventListener ('load', function () {
// gambar dimuat
......
});
img.addeventListener ('error', function () {
// ada yang salah
......
});
Ada dua masalah dengan kode di atas:
A. IMG sebenarnya telah dimuat, dan fungsi callback beban terikat saat ini. Akibatnya, panggilan balik tidak akan dieksekusi, tetapi masih berharap untuk menjalankan fungsi callback yang sesuai.
Salinan kode adalah sebagai berikut:
var img = document.queryselect (#ID);
function load () {
...
}
if (img.complete) {
memuat();
} kalau tidak {
img.addeventListener ('load', load);
}
img.addeventListener ('error', function () {
// ada yang salah
......
});
B. Tidak dapat menangani pengecualian dengan baik
Kesimpulan: Mekanisme acara paling cocok untuk menangani peristiwa berulang pada objek yang sama, dan tidak perlu mempertimbangkan peristiwa tersebut sebelum fungsi callback terikat.
1.3 Perpustakaan Kontrol Asinkron
Perpustakaan asinkron saat ini terutama mencakup Q, when.js, win.js, rsvp.js, dll.
Karakteristik dari perpustakaan ini adalah bahwa kode ini linier dan dapat ditulis dari atas ke bawah, sejalan dengan kebiasaan alami.
Hal -hal buruk juga berbeda dalam gaya, yang tidak nyaman untuk membaca dan meningkatkan biaya belajar.
1.4 Janji
Janji diterjemahkan ke dalam bahasa Cina sebagai janji. Secara pribadi, setelah selesai secara tidak sinkron, itu akan memberikan hasil eksternal (keberhasilan atau kegagalan) dan berjanji bahwa hasilnya tidak akan berubah lagi. Dengan kata lain, janji mencerminkan nilai hasil pengembalian akhir dari suatu operasi (janji mewakili nilai akhirnya yang dikembalikan dari satu penyelesaian operasi). Saat ini, janji telah diperkenalkan ke dalam spesifikasi ES6, dan browser canggih seperti Chrome dan Firefox telah menerapkan metode asli ini secara internal, yang cukup nyaman untuk digunakan.
Berikut ini adalah karakteristik janji dari aspek -aspek berikut:
1.4.1 Status
Ini berisi tiga negara: tertunda, terpenuhi, dan ditolak. Tiga negara hanya dapat menjalani dua transisi (dari yang tertunda ---> terpenuhi, tertunda-> ditolak), dan transisi negara hanya dapat terjadi sekali.
1.4.2 Lalu metode
Metode kemudian digunakan untuk menentukan fungsi callback setelah acara asinkron selesai.
Metode ini dapat dikatakan sebagai metode janji jiwa, yang membuat janji penuh sihir. Ada beberapa manifestasi spesifik sebagai berikut:
a) Kemudian metode mengembalikan janji. Ini memungkinkan operasi serial dari beberapa operasi asinkron.
Mengenai lingkaran kuning 1 pada gambar di atas, pemrosesan nilai adalah bagian yang lebih rumit dari janji. Pemrosesan nilai dibagi menjadi dua situasi: objek janji dan objek non-janji.
Ketika nilainya bukan tipe janji, cukup gunakan nilai sebagai nilai parameter dari tekad janji kedua; Ketika itu adalah tipe janji, status dan parameter Promise2 sepenuhnya ditentukan oleh nilai. Dapat dipertimbangkan bahwa PromSie2 adalah boneka bernilai, dan Promise2 hanyalah jembatan yang menghubungkan asinkron yang berbeda.
Salinan kode adalah sebagai berikut:
Janji.prototype.then = function (onfulfilled, onrejected) {
Return New Promise (Function (Resolve, Reject) {// Janji di sini ditandai sebagai janji2
menangani({
onfulfilled: onfulfilled,
OnREJECTED: OnReJECTED,
tekad: tekad,
Tolak: Tolak
})
});
}
fungsi fungsi (ditangguhkan) {
var handlefn;
if (state === 'terpenuhi') {
handlefn = ditangguhkan.onfulfilled;
} lain jika (state === 'ditolak') {
handlefn = ditangguhkan.
}
var ret = handlefn (nilai);
Deferred.Resolve (ret); // Perhatikan bahwa tekad saat ini adalah tekad janji2
}
function resolve (val) {
if (val && typeof val.then === 'function') {
val.then (tekad); // Jika val adalah objek janji atau objek janji kelas, keadaan janji2 sepenuhnya ditentukan oleh val
kembali;
}
if (callback) {// callback adalah fungsi panggilan balik yang ditentukan
callback (val);
}
}
b) Konversi antara beberapa perpustakaan asinkron yang berbeda diimplementasikan.
Ada objek yang disebut Thenable in Asynchronous, yang mengacu pada objek dengan metode kemudian. Selama objek objek memiliki metode kemudian, itu dapat dikonversi, misalnya:
Salinan kode adalah sebagai berikut:
var ditangguhkan = $ ('aa.Ajax'); // !! ditangguhkan.
var p = janji.resolve (ditangguhkan);
p.then (......)
1.4.3 Janji CommonJS/A Spesifikasi
Saat ini, ada spesifikasi janji/a dan janji/a+ untuk spesifikasi mengenai janji, yang menunjukkan bahwa implementasi janji cukup rumit.
Salinan kode adalah sebagai berikut:
Kemudian (Dipenuhi Handler, ditolak Handler, ProgressHandler)
1.4.4 Catatan
Fungsi panggilan balik dalam janji membagikan nilai. Dalam pemrosesan hasil, nilainya dilewati sebagai parameter ke fungsi panggilan balik yang sesuai. Jika nilainya adalah objek, berhati -hatilah agar tidak dengan mudah memodifikasi nilainya.
Salinan kode adalah sebagai berikut:
var p = janji.resolve ({x: 1});
p.then (function (val) {
console.log ('Callback pertama:'+val.x ++);
});
p.then (function (val) {
console.log ('panggilan balik kedua:' + val.x)
})
// panggilan balik pertama: 1
// panggilan balik kedua: 2
1.5 Generator
Semua metode di atas didasarkan pada fungsi callback untuk menyelesaikan operasi asinkron, dan mereka tidak lebih dari merangkum fungsi callback. ES6 mengusulkan generator, yang menambah cara untuk menyelesaikan operasi asinkron dan tidak lagi diselesaikan berdasarkan fungsi callback.
Fitur terbesar dari generator adalah dapat menjeda dan memulai kembali fungsi, yang sangat kondusif untuk menyelesaikan operasi asinkron. Menggabungkan jeda generator dengan penanganan pengecualian Promise dapat menyelesaikan masalah pemrograman asinkron lebih elegan. Referensi Implementasi Khusus: Kyle Simpson
2. Masalah dengan pemrograman asinkron
2.1 Penanganan Pengecualian
A) Acara asinkron mencakup dua tautan: mengeluarkan permintaan asinkron dan hasil pemrosesan. Kedua tautan ini terhubung melalui loop acara. Kemudian saat mencoba menangkap untuk melakukan pengecualian, Anda harus menangkapnya.
Salinan kode adalah sebagai berikut:
mencoba {
asyncevent (callback);
} catch (err) {
......
}
Kode di atas tidak dapat menangkap pengecualian dalam panggilan balik, dan hanya dapat memperoleh pengecualian dalam proses permintaan. Ini memiliki masalah: Jika penerbitan permintaan dan pemrosesan permintaan diselesaikan oleh dua orang, maka ada masalah saat menangani pengecualian?
b) Janji mengimplementasikan pengiriman pengecualian, yang membawa beberapa manfaat untuk memastikan bahwa kode tidak diblokir dalam proyek aktual. Namun, jika ada banyak peristiwa asinkron, tidak mudah untuk mengetahui peristiwa asinkron mana yang menghasilkan pengecualian.
Salinan kode adalah sebagai berikut:
// Deskripsi adegan: Tampilkan informasi alarm harga di CRM, termasuk informasi kompetitif. Namun, butuh waktu lama untuk mendapatkan informasi kompetitif. Untuk menghindari permintaan yang lambat, backend membagi rekor menjadi dua bagian untuk mendapatkannya secara terpisah.
// Langkah 1: Dapatkan informasi alarm harga, selain informasi kompetisi
fungsi getpricealAmdata () {
Return New Promise (Function (Resolve) {
Y.io (url, {
Metode: 'dapatkan',
Data: Params,
di: function () {
Sukses: function (id, data) {
tekad (alarmData);
}
}
});
});
}
// Setelah mendapatkan informasi alarm, pergi untuk mendapatkan informasi kompetisi
getpricealAmdata (). Kemudian (function (data) {
// rendering data, selain informasi kompetitif
render (data);
Return New Promise (Function (Resolve) {
Y.io (url, {
Metode: 'dapatkan',
Data: {AlarmList: Data},
di: function () {
Sukses: function (id, compdata) {
tekad (compdata);
}
}
});
});
}) // Setelah mendapatkan semua data, rendering informasi persaingan
.then (function (data) {
// memberikan informasi penawaran
render (data)
}, function (err) {
// Penanganan pengecualian
console.log (err);
});
Kode di atas dapat dikonversi ke yang berikut:
Salinan kode adalah sebagai berikut:
mencoba{
// Dapatkan informasi alarm selain kompetisi
var alarmData = alarmDataExceptCompare ();
render (alarmData);
// Pertanyaan Informasi Persaingan Berdasarkan Informasi Alarm
var dibandingkan = getCompareInfo (alarmData);
render (dibandingkan);
} catch (err) {
console.log (err.message);
}
Dalam contoh di atas, pengecualian ditangani di akhir, sehingga ketika pengecualian terjadi di tautan tertentu, kita tidak dapat mengetahui dengan tepat peristiwa mana yang dihasilkan.
2.2 JQuery. Masalah yang Diperoleh
Operasi asinkron juga diimplementasikan dalam jQuery, tetapi mereka tidak mematuhi spesifikasi Promise/A+ dalam implementasi, dan terutama tercermin dalam aspek -aspek berikut:
A. Jumlah parameter: Janji standar hanya dapat menerima satu parameter, sementara jQuery dapat melewati beberapa parameter
Salinan kode adalah sebagai berikut:
fungsi asyncinjQuery () {
var d = baru $ .deferred ();
setTimeout (function () {
D.Resolve (1, 2);
}, 100);
return d.promise ()
}
asyncinjQuery (). lalu (function (val1, val2) {
console.log ('output:', val1, val2);
});
// output: 1 2
B. Penanganan pengecualian dalam pemrosesan hasil
Salinan kode adalah sebagai berikut:
fungsi asyncinpromise () {
Return New Promise (Function (Resolve) {
setTimeout (function () {
var jsonstr = '{"name": "mt}';
Resolve (JSonstr);
}, 100);
});
}
asyncinpromise (). Kemudian (function (val) {
var d = json.parse (val);
console.log (d.name);
}). Kemudian (null, function (err) {
console.log ('tunjukkan kesalahan:' + err.message);
});
// Tampilkan kesalahan: Akhir input yang tidak terduga
fungsi asyncinjQuery () {
var d = baru $ .deferred ();
setTimeout (function () {
var jsonstr = '{"name": "mt}';
D.Resolve (jsonstr);
}, 100);
return d.promise ()
}
asyncinjQuery (). lalu (function (val) {
var d = json.parse (val);
console.log (d.name);
}). Kemudian (function (v) {
console.log ('Success:', v.name);
}, function (err) {
console.log ('tunjukkan kesalahan:' + err.message);
});
// Sintakserror Tanpa Diputus: Akhir Input yang Tidak Terduga
Dapat dilihat dari ini bahwa janji memproses hasil fungsi callback, yang dapat menangkap pengecualian selama pelaksanaan fungsi callback, tetapi jQuery. Deferred tidak bisa.