UI响应和JavaScript

swi*_*ure 4 javascript user-interface

我有一大堆数据要在谷歌地图上绘制.由于数据集大小,谷歌地图总是在绘制所有点之前冻结几秒钟.我在加载时使用了一个动画旋转圆圈来显示它正在进行中.但最终用户更愿意看到行动.他们希望逐步在地图上绘制数据,而不是一次性绘制所有数据.由于javascript不支持多线程,最好的方法是什么?

zak*_*rya 7

Javascript引擎通过从队列中排序来逐个执行函数.可以通过脚本或用户操作(事件处理程序)将函数放在那里.因此,想法是将长时间运行的任务分成小的短期运行子任务,并以这种方式将它们提供给这个"队列",以便它们可以与响应用户操作的功能混合在一起.
这可以通过调用窗口的setTimeout(零延迟)并将子任务作为函数传递来完成.因此,您将有机会提前执行UI事件处理程序

function plotSpot(spot) {
    // adding spots to map
};
var spots = [1,2,3,4,5,6,7,8,9,10,11,12];
var plotSpotsBatch;
plotSpotsBatch = function() {
    var spotsInBatch = 10;
    while(spots.length > 0 && spotsInBatch--) {
        var spot = spots.shift();
        plotSpot(spot);
    }
    if (spots.length > 0) {
        setTimeout(plotSpotsBatch, 0);
    }
};
plotSpotsBatch();
Run Code Online (Sandbox Code Playgroud)

这是Array原型的扩展:

Array.prototype.forEachInBatches = function(batchSize, func) {
    var arr = this;
    var i = 0;
    var doer;
    doer = function() {
        setTimeout(function() {
            for (var stopBatch = i + batchSize; i < stopBatch && i < arr.length; i++) {
                func(arr[i], i);
            }
            if (i < arr.length) {
                doer();
            }
        }, 0);
    };
    doer();
};
Run Code Online (Sandbox Code Playgroud)

用法示例(您必须在文档中的某处具有id为'spot'的div).要查看差异,请将批次大小设置为等于点数:

var spots = [];
for (var i = 0; i < 10000; i++) {
    spots.push('{x: ' + Math.ceil(Math.random() * 180) + ', y: ' + Math.ceil(Math.random() * 180) + '}');
}
spots.forEachInBatches(10, function(spot, i) {
    document.getElementById('spots').innerHTML += spot + (i < spots.length ? '; ' : '');
});
Run Code Online (Sandbox Code Playgroud)