新聞中心
需求
我最近在做一個(gè)需求:批量去往數(shù)據(jù)庫(kù)里存儲(chǔ)一些東西,數(shù)量可能一次性達(dá)到幾百個(gè),也就意味著我需要一次性往數(shù)據(jù)庫(kù)里存儲(chǔ)幾百次,我是這么做的:

我們提供的服務(wù)有:網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、涇源ssl等。為近千家企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的涇源網(wǎng)站制作公司
const save = (data) => {
// 數(shù)據(jù)庫(kù)操作(Promise)
return insert(data)
}
const datas = [...幾百個(gè)數(shù)據(jù)]
// 進(jìn)行存儲(chǔ)
Promise.all(datas.map(save))
被呵斥
正當(dāng)我覺(jué)得這個(gè)需求很輕松的時(shí)候。在 Code Review 上,我被團(tuán)隊(duì)的大佬們給呵斥了一頓,理由是:存儲(chǔ)的操作發(fā)生在服務(wù)器,服務(wù)器是很脆弱的,你一次性存儲(chǔ)幾百個(gè),服務(wù)器崩了怎么辦?
隨后大佬們提出解決方案:控制并發(fā),大佬們是真的強(qiáng),感覺(jué)這種東西已經(jīng)是大佬們的常規(guī)操作了。
控制Promise.all并發(fā)
意思就是,比如我有幾百個(gè)存儲(chǔ)操作,我不能一次性去全部執(zhí)行,而是要控制一次性只能執(zhí)行10個(gè)操作,10個(gè)中有一個(gè)執(zhí)行完了,就拿還沒(méi)執(zhí)行的操作補(bǔ)上去,就這樣一直到這幾百個(gè)操作全部執(zhí)行完為止。
其實(shí)很簡(jiǎn)單,可以直接用庫(kù),比如async-pool、es6-promise-pool、p-limit,只要是能用庫(kù)的,我建議不要自己去寫(xiě),因?yàn)椴欢ㄒ蛩睾芏啵阕约簩?xiě)的肯定沒(méi)有庫(kù)寫(xiě)的好,你說(shuō)呢~
簡(jiǎn)單實(shí)現(xiàn)
看到一位兄弟實(shí)現(xiàn)的挺不錯(cuò)的,鏈接:https://segmentfault.com/a/1190000016389127
這是async-pool這個(gè)庫(kù)的核心源碼:
function asyncPool(poolLimit, array, iteratorFn) {
let i = 0;
const ret = [];
const executing = [];
const enqueue = function () {
// 邊界處理,array為空數(shù)組
if (i === array.length) {
return Promise.resolve();
}
// 每調(diào)一次enqueue,初始化一個(gè)promise
const item = array[i++];
const p = Promise.resolve().then(() => iteratorFn(item, array));
// 放入promises數(shù)組
ret.push(p);
// promise執(zhí)行完畢,從executing數(shù)組中刪除
const e = p.then(() => executing.splice(executing.indexOf(e), 1));
// 插入executing數(shù)字,表示正在執(zhí)行的promise
executing.push(e);
// 使用Promise.rece,每當(dāng)executing數(shù)組中promise數(shù)量低于poolLimit,就實(shí)例化新的promise并執(zhí)行
let r = Promise.resolve();
if (executing.length >= poolLimit) {
r = Promise.race(executing);
}
// 遞歸,直到遍歷完array
return r.then(() => enqueue());
};
return enqueue().then(() => Promise.all(ret));
}大概的邏輯可以總結(jié)為:
- 從array第1個(gè)元素開(kāi)始,初始化promise對(duì)象,同時(shí)用一個(gè)executing數(shù)組保存正在執(zhí)行的promise
- 不斷初始化promise,直到達(dá)到poolLimt
- 使用Promise.race,獲得executing中promise的執(zhí)行情況,當(dāng)有一個(gè)promise執(zhí)行完畢,繼續(xù)初始化promise并放入executing中
- 所有promise都執(zhí)行完了,調(diào)用Promise.all返回
使用方式:
const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i));
return asyncPool(2, [1000, 5000, 3000, 2000], timeout).then(results => {
...
});
當(dāng)前標(biāo)題:幾百個(gè)數(shù)據(jù),Promise.all沒(méi)做控制并發(fā)?那你心可真大?。?
文章轉(zhuǎn)載:http://m.fisionsoft.com.cn/article/dhjgpch.html


咨詢
建站咨詢
