Open FrankKai opened 4 years ago
最近也遇到了一个并发请求导致服务端插入重复数据报错的坑,是因为前端并发了多个相同的Create请求,服务端多线程提交数据库事务存在冲突,所以导致报错。但是由于前端发送重复请求是相对较好的处理方式,所以最终改成了阻塞请求。 具体的前端实现方式,异步并发:Promise.all;同步阻塞:await。Promise.all异步并发与await同步阻塞。
async promiseAllAsyncConcurrence(items) { const promiseArr = []; for (let i = 0; i < 9; i++) { promiseArr[i] = new Promise((resolve)=>{ setTimeout(()=>{ resolve(items[i]); }, Math.random()*1000) }) } return Promise.all(promiseArr); } const sourceArr = ['foo', 'bar', 'baz'] const resultArr = await promiseAllAsyncConcurrence(sourceArr);
awaitSequenceSync(item) { return new Promise((resolve)=>{ setTimeout(()=>{ resolve(items); }, Math.random()*1000) }) } const sourceArr = ['foo', 'bar', 'baz'] const resultArr = []; for (let i = 0; i < 9; i++) { // eslint-disable-next-line resultArr[i] = await awaitSequenceSync(sourceArr[i]); }
注意:如果不添加会报ESLint error: Unexpected await inside a loop no-await-in-loop
ESLint error: Unexpected await inside a loop no-await-in-loop
async promiseAllAsyncConcurrence(items) { const promiseArr = []; for (let i = 0; i < 9; i++) { promiseArr[i] = new Promise((resolve)=>{ setTimeout(()=>{ new Promise((resolve)=>{ setTimeout(()=>{ resolve(items[i]); }, Math.random()*1000) }) }, (i+1)*500) // 每个请求间隔500ms }) } return Promise.all(promiseArr); } const sourceArr = ['foo', 'bar', 'baz'] const resultArr = await promiseAllAsyncConcurrence(sourceArr);
/** * 串行控制:一个接着一个发请求 * @param {*} items * @param {*} asyncFunc */ function seriesFlow(items, asyncFunc) { const result = []; items.forEach(async (item, i) => { result[i] = await asyncFunc(item); }); return result; }
/** * 并行控制:请求一次性并行发出 * @param {*} items * @param {*} asyncFunc */ function parallelFlow(items, asyncFunc) { return new Promise((resolve, reject) => { const promises = []; items.forEach((item, i) => { promises[i] = asyncFunc(item); }); return Promise.all(promises) .then(data => { resolve(data); }) .catch(err => { reject(err); }); }); }
使用示例可以到我的个人npm ujf查看:https://www.npmjs.com/package/ujf 上面源码位置:https://github.com/FrankKai/UJF/blob/master/src/task.js
Series会在之前的一个函数完成后再执行下一个函数,最后一个函数执行完毕时进入最终回调。
_.series([ function (callback) { setTimeout(function () { console.log('one'); callback(); }, 25); }, function (callback) { setTimeout(function () { console.log('two'); callback(); }, 0); } ], ()=>{ // do something... });
Parallel会同时执行所有函数,当所有函数执行完毕时进入最终回调。
_.parallel([ function (callback) { setTimeout(function () { console.log('one'); callback(); }, 25); }, function (callback) { setTimeout(function () { console.log('two'); callback(); }, 0); } ], ()=>{ // do something... });
参考资料http://caolan.github.io/nimble/
参考资料:http://bluebirdjs.com/docs/api/promise.mapseries.html
参考资料:http://bluebirdjs.com/docs/api/promise.all.html
实际项目中遇到的串行并行控制问题
最近也遇到了一个并发请求导致服务端插入重复数据报错的坑,是因为前端并发了多个相同的Create请求,服务端多线程提交数据库事务存在冲突,所以导致报错。但是由于前端发送重复请求是相对较好的处理方式,所以最终改成了阻塞请求。 具体的前端实现方式,异步并发:Promise.all;同步阻塞:await。Promise.all异步并发与await同步阻塞。
并发式的Promise.all(导致后端服务出问题)
阻塞式的await(后端服务正常运转)
注意:如果不添加会报
ESLint error: Unexpected await inside a loop no-await-in-loop
并发的Promise.all添加setTimeout定时器(不推荐)
如何使用async,await实现串控制
如何使用promise.all实现并行控制
使用示例可以到我的个人npm ujf查看:https://www.npmjs.com/package/ujf 上面源码位置:https://github.com/FrankKai/UJF/blob/master/src/task.js
如何使用第三方库Nimble实现串并行控制
Nimble串行控制
Series会在之前的一个函数完成后再执行下一个函数,最后一个函数执行完毕时进入最终回调。
Nimble并行控制
Parallel会同时执行所有函数,当所有函数执行完毕时进入最终回调。
参考资料http://caolan.github.io/nimble/
如何使用第三方库blueBird实现串并行控制
Promise.mapSeries实现串行控制
参考资料:http://bluebirdjs.com/docs/api/promise.mapseries.html
Promise.all实现并行控制
参考资料:http://bluebirdjs.com/docs/api/promise.all.html