开发者

In JavaScript, How to make make changes to document elements while complex functions are performed?

开发者 https://www.devze.com 2023-03-28 09:55 出处:网络
I\'m processing a large amount of data with JavaScript. I put a circular gif and a progress div to show how much progress has been done in creating the model. However, when it gets to the bulky part o

I'm processing a large amount of data with JavaScript. I put a circular gif and a progress div to show how much progress has been done in creating the model. However, when it gets to the bulky part of code processing, the loading gif stops spinning and the percentage updating stops working. (until the very end for a split second)

This is the block of code that freezes the gif.

    // convert binary normals to ascii
    for(i=0;i<norms.length;i++){   //<-- the array length is about 200,000, and could be larger
        normals.push(toAscii(norms[i], mins[5], maxes[5]));  //nx
        no开发者_JAVA技巧rmals.push(toAscii(norms[i+1], mins[6], maxes[6]));//ny
        normals.push(toAscii(norms[i+2], mins[7], maxes[7]));//nz
        i = i+2; //skip next 2 as they're already converted

        percentComplete = (normals.length/norms.length)*100;
        percentComplete = Math.round(percentComplete);

        document.getElementById('loadingScrn').innerHTML = "Processing " 
        +percentComplete + "%" + " Complete"; //<-- The loading gif is right below this element on the webpage and neither update while this function is running  
    } 

How can I get the browser update the display while JavaScript functions process large data? Is there a way to thread activities so that both updating the Document and JavaScript processing occur simultaneously?


JavaScript runs on the same thread as the browser GUI in most cases (or the tab's GUI, if each tab is given its own process). You will have to break the work into small pieces and schedule the next piece from the currently-executing one using setTimeout().

For example, this might work in your case:

var i = 0;

function doWork() {
    do {
        // One iteration here...

        i++;
    } while (i % 100 != 0 && i < norms.length);

    // ^^^
    // Break work into pieces of 100 elements each; adjust this
    // number as needed.

    if (i < norms.length) {
        setTimeout(doWork, 1);
    }
}

setTimeout(doWork, 1);

See this example jsfiddle.


You are correctly observing that JavaScript code runs in the same thread as the document's interface, blocking it when you perform large operations.

Web Workers are a JavaScript feature that is designed to help solve this problem. It allows you to spawn new threads that run along side the document, and communicate results asynchronously as they become available. Unfortunately this is not yet supported in Internet Explorer, but it is planned for IE10, and other browsers already support it.

As suggested by cdhowie and Jonathan M, another solution (inferior, but supported everywhere) is to use setTimeout to pause your code occasionally and let the browser respond to events. You would need to make your code somewhat more complicated to make this work. To give you an idea, to pause every 1000 items you would do something like this:

var workSliceSize = 1000;
var doWorkFromIndex = function(start) {
    for (var i = start; i < norms.length; i++) {
        if (i - start > workSliceSize) {
            setTimeout(0, doWorkFromIndex, i + 1);
            break;
        }

        normals.push... // your code here
    }
}
doWorkFromIndex(0);


Try setTimeout(). It processes code asynchronously. I've used it to free up the screen processing by doing:

setTimeout(function() {
    // the stuff I want to accomplish while keeping the gif going
    },
    0
);

Here I've set the timeout time period at zero milliseconds, but it can be whatever you want.


Try

var i = 0;

function processNormals() {
    normals.push(toAscii(norms[i], mins[5], maxes[5]));  //nx
    normals.push(toAscii(norms[i+1], mins[6], maxes[6]));//ny
    normals.push(toAscii(norms[i+2], mins[7], maxes[7]));//nz
    i = i+3; //skip next 2 as they're already converted
    percentComplete = (normals.length/norms.length)*100;
    percentComplete = Math.round(percentComplete);

    document.getElementById('loadingScrn').innerHTML = "Processing "  +percentComplete + "%" + " Complete";

    if(i < norms.length) setTimeout(processNormals, 20);
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号