Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/455.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在浏览器端高效地处理巨大的javascript数组(20 mil坐标的数组)?_Javascript_Arrays_Performance_Google Chrome_D3.js - Fatal编程技术网

如何在浏览器端高效地处理巨大的javascript数组(20 mil坐标的数组)?

如何在浏览器端高效地处理巨大的javascript数组(20 mil坐标的数组)?,javascript,arrays,performance,google-chrome,d3.js,Javascript,Arrays,Performance,Google Chrome,D3.js,这是我的密码: <!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: 1

这是我的密码:

<!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>

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

编辑:

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

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

1) 进程在创建阵列期间冻结: 将20 mil项目加载到阵列可能需要一段时间,我建议不要这样做。有不止一种方法可以实现这一点,但我会尽可能多地将沉重的循环逻辑转移到javascript之外,并可能转移到web服务。这也有其自身的挑战,比如试图将2000万件物品发送回客户机,这是一个坏主意。但是,如果您可以将其划分为可管理的坐标组(最多20-100个),然后根据需要进行多个web服务调用(使用类似JQuery Ajax方法的方法),那么您的javascript所要担心的就是添加这些项。这将在一段时间内向您传输数据,因此不要期望它是即时的,但如果浏览器在20 mil时间内难以通过坐标创建功能循环,则不应冻结浏览器

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);
}
var renderingCounter=0;
var asyncTimer=null;//使渲染计时器保持全局,以防止运行重复的渲染
函数StartRender(){
//测试现有异步渲染是否正在运行
if(asyncTimer!=null){
//现有异步计时器,清除计时器并清除画布
清除间隔(异步定时器);
渲染计数器=0;
//清除画布的代码。。
};
//创建间隔对象
var asyncTimer=setInterval(函数(){
//在每次开始渲染时,测试是否已渲染所有点
if(renderingCounter>=pointArray.length){
//杀死异步定时器
清除间隔(异步定时器);
asyncTimer=null;
renderingCounter=0;//重置计数器
返回;
};
而(renderingCounter<100){//仅绘制100个项目
如果(renderingCounter>=pointArray.length){//请确保没有超出数组边界
返回;
};
//执行该点的显示代码
};//循环
}, 40);
}
上面的代码将渲染过程拆分为100个点组。在完成一个组时,它会暂停40毫秒,这将在主线程上释放足够的时间,以允许继续执行其他项目(如UI)。全局变量renderingCounter将保持数组中的当前进度。如果函数在渲染过程中被重新调用,代码还会检查当前正在运行的渲染计时器(在本例中,它会终止当前渲染并重置它)。如果渲染计时器仍然导致挂起,可以增加暂停间隔


这两种实现异步执行的方法应该提供足够的灵活性,允许从服务器端web服务(如果您曾经这样做过)进行渲染或读取数据,同时保持流畅的ui,Javascript是一个单线程系统。本质上创建回调(如setTimeout)的函数仍然会杀死单线程系统

编辑:

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

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

1) 进程在创建阵列期间冻结: 将20 mil项目加载到阵列可能需要一段时间,我建议不要这样做。有不止一种方法可以实现这一点,但我会尽可能多地将沉重的循环逻辑转移到javascript之外,并可能转移到web服务。这也有其自身的挑战,比如试图将2000万件物品发送回客户机,这是一个坏主意。但是,如果您可以将其划分为可管理的坐标组(最多20-100个),然后根据需要进行多个web服务调用(使用类似JQuery Ajax方法的方法),那么您的javascript所要担心的就是添加这些项。这将在一段时间内向您传输数据,因此不要期望它是即时的,但如果浏览器在20 mil时间内难以通过坐标创建功能循环,则不应冻结浏览器

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);
}
var renderingCounter=0;
var asyncTimer=null;//使渲染计时器保持全局,以防止运行重复的渲染
函数StartRender(){
//测试现有异步渲染是否正在运行
if(asyncTimer!=null){
//现有异步计时器,清除计时器并清除画布
清除间隔(异步定时器);
渲染计数器=0;
//清除画布的代码。。
};
//创建间隔对象
var asyncTimer=setInterval(函数(){
//在每次开始渲染时,测试是否已渲染所有点
if(renderingCounter>=pointArray.length){
//杀死异步定时器
清除间隔(异步定时器);
asyncTimer=null;
function createPictureArray() {
    var res, i, max_i;
    var canvasEl = d3.select('#test').node();
    var ctx = canvasEl.getContext('2d');
    var data;

    res = ctx.getImageData(0, 0, width, height);
    data = res.data;
    for (i = 0, max_i = data.length; i < max_i; i++) {
        data[i] = 255;
    }
    return res;
}

function generateData(size) {
    var i, x, y, s, res, data, randomX, randomY;

    randomX = d3.random.normal(width/2 , 80);
    randomY = d3.random.normal(height/2, 80);    

    res = createPictureArray();
    data = res.data;
    for (i = 0; i < size; i++) {

        x = parseInt(randomX());
        y = parseInt(randomY());
        s = 4 * y * width + 4 * x;
        if (data.length > s && data[s + 1] !== 0) {
            data[s + 1] = 0;
            data[s + 2] = 0;
        }
    }
    return res;
}

function main() {
    var canvasEl = d3.select('#test').node();
    var ctx = canvasEl.getContext('2d');
    width = canvasEl.width;
    height = canvasEl.height;
    data = generateData(2000000);
    ctx.putImageData(data, 0, 0);

}
main()