gpt4 book ai didi

javascript - 我如何在浏览器端有效地处理巨大的javascript数组(2000万个坐标的数组)?

转载 作者:行者123 更新时间:2023-11-28 12:35:58 25 4
gpt4 key购买 nike

这是我的代码:

<!DOCTYPE html>

<html>
<head>
<title>d3 Practice</title>
</head>

<body>
<script src="./vislibs/d3.v3.min.js"></script>
<canvas id="test" width="1024" height="768" style="border: 1px solid black;"></canvas>
<script>
function generate_data(size){
var randomX = d3.random.normal(width/2 , 80),
randomY = d3.random.normal(height/2, 80);

var data = d3.range(size).map(function() {
return [
randomX(),
randomY()
];
});
return data
}
function main() {
var canvasEl = d3.select('#test').node();

// get 2d context to draw on
var ctx = canvasEl.getContext('2d');
width = canvasEl.width
height = canvasEl.height
data=generate_data(20000000)
alert("data generated")
// set fill color of context
var x = 0
ctx.fillStyle = 'red';
batch_size = 10000

debugger // Cannot step into requestAnimationFrame(draw_loop) at all , freezing eternity
draw_loop = function () {
if (x<=data.length-1) {
for (i in d3.range(0,batch_size)){

//console.log(x)
ctx.fillRect(data[x][0], data[x][1], 2, 2);
x = x+1

}

setTimeout(draw_loop,100);
}
}

requestAnimationFrame(draw_loop)
//alert("done reqanim")
}
main()
//init()

</script>

</body>
</html>

这将在生成 generate_data(20000000) 后卡住浏览器,甚至无需转到 requestAnimationFrame(draw_loop) 。我在没有 requestAnimationFramesetTimeout 的情况下进行了测试,并一次渲染所有内容,但工作正常,但它会卡住浏览器一点。卸载到服务器似乎是一个很好的解决方案,但我想知道为什么暂停(setTimeout 和 requestAnimiationFrame)会导致浏览器无限卡住而不是将控制权交给浏览器。

在 Linux 上测试,Chromium 版本 26.0.1410.43 (189671)。

浏览器的内存使用量约为 1.4 GB,仅在 generate_data(20000000) 完成后打开该脚本的一个选项卡,但我的笔记本电脑上有 6 GB 的可用内存。那么有没有什么有效的方法来处理呢? (不会导致无响应或无限卡住)

编辑:

这里正在工作 JSFiddle 2 mil rectangles

这将卡住您的浏览器。 20 mil rectangles

如果没有 setTimeout 或 requestAnimationFrame ,这将导致 1-2 次无响应,但可以很好地渲染到最后而不会卡住。 20 mil rectangles without pausing functions

概念证明,没有渲染代码,生成数据,数据生成后您将看到警报框,但浏览器一点击requestAnimationFrame就被卡住。 (2000万点)will freeze browser ,

function generate_data(size){
var randomX = d3.random.normal(width/2 , 80),
randomY = d3.random.normal(height/2, 80);

var data = d3.range(size).map(function() {
return [
randomX(),
randomY()
];
});
return data
}
function main() {
var canvasEl = d3.select('#test').node();

// get 2d context to draw on (the "bitmap" mentioned earlier)
var ctx = canvasEl.getContext('2d');
width = canvasEl.width
height = canvasEl.height
data=generate_data(20000000)
alert("data generated")
// set fill color of context
var x = 0
ctx.fillStyle = 'red';
batch_size = 10000

//debugger // Cannot step into requestAnimationFrame(draw_loop) at all , freezing eternity
draw_loop = function () {
if (x<=data.length-1) {
nada=""
x=x+batch_size
setTimeout(draw_loop,100);
}
}

requestAnimationFrame(draw_loop)
alert("done reqanim")
}
main()

2 mil points version , without rendering code , that works

最佳答案

Javascript 是一个单线程系统。像 setTimeout 这样本质上创建回调的函数仍然会杀死单线程系统。

编辑:

根据评论,有一些创造性的方法可以让单线程 Javascript 产生异步执行大型逻辑函数的错觉,从而释放执行点击处理程序等内容的过程。

@V3ss0n 根据代码中进程卡住发生的位置,您有以下几个选项:

1) 进程在创建数组期间卡住:将 2000 万个项目加载到数组中可能需要一段时间,我建议不要这样做。有不止一种方法可以解决这个问题,但我会尽可能地将繁重的循环逻辑移至 JavaScript 之外,并可能移至 Web 服务。这有其自身的挑战,例如尝试将 2000 万件元素发送回客户,这是一个坏主意。但是,如果您可以将其分成可管理的坐标组(最多 20-100),然后根据需要进行多个 Web 服务调用(使用 JQuery Ajax 方法 http://api.jquery.com/jQuery.ajax/ 之类的东西),那么您的 javascript 所需要担心的就是附加项目。这将在一段时间内向您传输数据,因此不要期望它是即时的,但如果浏览器在循环坐标创建函数 2000 万次时遇到困难,则不应卡住浏览器。

2) 渲染每个单独点期间进程卡住:对此的修复更具创意,如果您不想使用 Web 服务,也可以用于上述过程。首先看下面的代码:

    var renderingCounter = 0;
var asyncTimer = null; // keep the render timer global to prevent duplicate renders from being run

function StartRender(){
// test if existing async render is running
if(asyncTimer != null){
// existing async timer, clear the timer and clear the canvas
clearInterval(asyncTimer);
renderingCounter = 0;

// code for clearing the canvas ..
};

// create interval object
var asyncTimer = setInterval(function (){
// at the begining of each start render, test if all points have been rendered
if(renderingCounter >= pointArray.length){
// kill the asynctimer
clearInterval(asyncTimer);
asyncTimer = null;
renderingCounter = 0; // reset the counter
return;
};

while(renderingCounter < 100){ // only draw 100 items
if(renderingCounter >= pointArray.length){ // make sure you are not out of array bounds
return;
};

// execute display code for that point
}; // loop
}, 40);
}

上面的代码将渲染过程分为 100 个点组。完成一组后,它会暂停 40 毫秒,这应该会在主线程上释放足够的时间,以允许继续执行其他项目(例如 UI)。全局变量renderingCounter将通过数组保持当前进度。如果函数在渲染期间被重新调用,代码还会检查当前正在运行的渲染计时器(在示例中,它会终止当前渲染并重置它)。如果渲染计时器仍然导致挂起,您可以增加暂停间隔。

这两种实现异步执行的方法应该提供足够的灵 active ,以允许从服务器端 Web 服务进行渲染或数据读取(如果您朝这个方向发展),同时仍然保持流畅的 ui

关于javascript - 我如何在浏览器端有效地处理巨大的javascript数组(2000万个坐标的数组)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16945006/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com