場景:想請求量較大的網路資料,比如想獲取1000條結果,但資料處理速度慢,有超時的風險,可以分成10次處理,每次處理100條;所有請求完成後再統一進行處理。
這樣的應用場景,可以這樣處理:
方案一:判斷請求到的資料條目
// 模擬網路請求
function fetch(url, callback) {
setTimeout(function (){
callback(null, {
subjects: [{
data: Math.round(Math.random() * 100)
}]
});
}, 2000);
}
// 實現方案1
function multiTask_1 () {
var arr = [];
var baseUrl = `https://api.douban.com/v2/movie/top250`;
for (var start = 0; start < 10; start++) {
var url = baseUrl + `?start=` + start + "&count=1";
fetch(url, function(error, res) {
var data = res.subjects;
arr = arr.concat(data);
// 呼叫完成後統一處理
if (arr.length === 10) {
console.log(arr);
}
});
}
}
將執行結果用arr.length來判斷,如果arr.length不像我們期望的那樣,比如由於網路傳輸或者處理異常,少一條,那麼我們將無法做後續的處理。這種處理方式強業務耦合;不具有普適性。
方案二:判斷非同步過程執行次數
// 方案2
function multiTask_2 () {
var taskWatcher = 0;
var arr = [];
var baseUrl = `https://api.douban.com/v2/movie/top250`;
for (var start = 0; start < 10; start++) {
taskWatcher++;
var url = baseUrl + `?start=` + start + "&count=1";
fetch(url, function(error, res) {
var data = res.subjects;
arr = arr.concat(data);
taskWatcher--;
if (taskWatcher === 0) {
console.log(arr);
}
});
}
}
方案2 的判斷條件,這裡的 taskWatcher 充當非同步任務執行情況的觀察員,
僅與非同步過程的呼叫次數有關,且與其他處理過程無關。那有沒有其他方案呢
方案三:Promise.all()
Promise.all(iterable) 方法返回一個 Promise, 它將在上述可迭代物件中的所有 Promise 被 resolve 之後被 resolve,或者在任一 Promise 被 reject 後被 reject。
function multiTask_3 () {
// var taskWatcher = 0;
var taskStack = [];
var arr = [];
var baseUrl = `https://api.douban.com/v2/movie/top250`;
for (var start = 0; start < 10; start++) {
taskStack.push(
new Promise((resolve, reject) => {
var url = baseUrl + `?start=` + start + "&count=1";
fetch(url, function(error, res) {
var data = res.subjects;
arr = arr.concat(data);
resolve();
});
})
);
}
Promise.all(taskStack).then(function () {
console.log(arr);
});
}
這種方式更具有通用性,如果非同步任務型別不同,也可以用這種方式來解決。不過應當注意reject的處理。避免其對最終處理的影響。
方案四: EventProxy
EventProxy是樸靈寫的,https://github.com/JacksonTian/eventproxy
var ep = new EventProxy();
var arr = [];
ep.after(`fetchData`, 10, function (list) {
list.forEach(function(item){
arr = arr.concat(item);
});
console.log(arr);
});
var baseUrl = `https://api.douban.com/v2/movie/top250`;
for (var start = 0; start < 10; start++) {
var url = baseUrl + `?start=` + start + "&count=1";
fetch(url, function(error, res) {
var data = res.subjects;
ep.emit(`fetchData`, data);
});
}
EventProxy基於事件訂閱/釋出模式,這裡的after 方法可以偵聽多次事件,回撥中儲存了多次非同步任務的資料結果的陣列;除此之外EventProxy還支援多個不同事件的偵聽和處理。