异步&分段处理海量数据

有一种并发合作方式,称为并发协作(cooperative concurrency)。这里的重点不再是通过
共享作用域中的值进行交互(尽管显然这也是允许的!)。这里的目标是取到一个长期运
行的“进程”,并将其分割成多个步骤或多批任务,使得其他并发“进程”有机会将自己
的运算插入到事件循环队列中交替运行。
举例来说,考虑一个需要遍历很长的结果列表进行值转换的 Ajax 响应处理函数。我们会
使用 Array#map(..) 让代码更简洁:

var res = [];
// response(..)从Ajax调用中取得结果数组
function response(data) {
// 添加到已有的res数组
res = res.concat(
// 创建一个新的变换数组把所有data值加倍
data.map( function(val){
return val * 2;
} )
);
}
// ajax(..)是某个库中提供的某个Ajax函数
ajax( "http://some.url.1", response );
ajax( "http://some.url.2", response );


如果 "http://some.url.1" 首先取得结果,那么整个列表会立刻映射到 res 中。如果记录
有几千条或更少,这不算什么。但是如果有像 1000 万条记录的话,就可能需要运行相当
一段时间了(在高性能笔记本上需要几秒钟,在移动设备上需要更长时间,等等)。
这样的“进程”运行时,页面上的其他代码都不能运行,包括不能有其他的 response(..)
调用或 UI 刷新,甚至是像滚动、输入、按钮点击这样的用户事件。这是相当痛苦的。
所以,要创建一个协作性更强更友好且不会霸占事件循环队列的并发系统,你可以异步地
批处理这些结果。每次处理之后返回事件循环,让其他等待事件有机会运行。
这里给出一种非常简单的方法:

var res = [];
// response(..)从Ajax调用中取得结果数组
function response(data) {
// 一次处理1000个
var chunk = data.splice( 0, 1000 );
// 添加到已有的res组
res = res.concat(
// 创建一个新的数组把chunk中所有值加倍
chunk.map( function(val){
return val * 2;
} )
);
// 还有剩下的需要处理吗?
if (data.length > 0) {
// 异步调度下一次批处理
setTimeout( function(){
response( data );
}, 0 );
}
}
// ajax(..)是某个库中提供的某个Ajax函数
ajax( "http://some.url.1", response );
ajax( "http://some.url.2", response );

我们把数据集合放在最多包含 1000 条项目的块中。这样,我们就确保了“进程”运行时
间会很短,即使这意味着需要更多的后续“进程”,因为事件循环队列的交替运行会提高
站点 /App 的响应(性能)

 

摘自《你不知道的javascript(中)》P155

posted @ 2019-05-13 16:49 LLLLily 阅读(...) 评论(...) 编辑 收藏