admin管理员组文章数量:1355694
I have created two buttons .One is named 'sync' and other is named 'async'.When i click 'sync' button ,it should process the big array using loops and it freezes the browser until the loop is pleted processing the larger array.When i press the 'async' button.it should process the same large array without freezing the browser.How to do this using setTimeOut function?
I have created two buttons .One is named 'sync' and other is named 'async'.When i click 'sync' button ,it should process the big array using loops and it freezes the browser until the loop is pleted processing the larger array.When i press the 'async' button.it should process the same large array without freezing the browser.How to do this using setTimeOut function?
Share Improve this question asked Aug 3, 2016 at 5:36 AmudhaVigneshwaranAmudhaVigneshwaran 1152 silver badges8 bronze badges 4- Try using Web Worker. – Rohan Veer Commented Aug 3, 2016 at 5:38
-
Perhaps not exactly what you're looking for (as you specifically mention
setTimeout
), but you might find this article on web workers helpful: html5rocks./en/tutorials/workers/basics – SimianAngel Commented Aug 3, 2016 at 5:39 -
In my view you can use
SetTimeInterval
, refer this link : stackoverflow./questions/6081443/… – Sunil Kumar Commented Aug 3, 2016 at 6:40 - @RohanVeer Still web worker freezes the browser.I created a separate javascript file in which array of 100000 index was processed and printed on console.Though it runs in separate thread,wht it freezes the browser?:( – AmudhaVigneshwaran Commented Aug 4, 2016 at 10:58
4 Answers
Reset to default 5Using async/await this in ES7 this gets pretty trivial. Example of long loop that takes too long
function main() {
const numOperations = 1000000000;
let sum = 0;
for (let i = 0; i < numOperations; ++i) {
sum += doSomeOperation(i);
}
console.log(sum);
}
main();
function doSomeOperation(v) {
return v * 1.1 / (v + 1);
}
Example of using async/await to make it yield to the browser once in a while
async function main() {
const numOperations = 1000000000;
const iterationsPerChunk = 10000000;
let sum = 0;
for (let i = 0; i < numOperations; ++i) {
if (i && i % iterationsPerChunk === 0) {
await oneMoment();
}
sum += doSomeOperation(i);
}
console.log(sum);
}
main();
function doSomeOperation(v) {
return v * 1.1 / (v + 1);
}
function oneMoment() {
return new Promise(resolve => setTimeout(resolve));
}
Picking a good value for iterationsPerChunk
might be harder. You could easily make some class that checks performance.now
and only calls await when a certain amount of time has passed, say 1/2 a second or 1 second. Each call to setTimeout
will yield for anywhere from 5ms to 20ms so you don't want to await too often but it does make it easy to use.
example using performance.now
async function main() {
const numOperations = 1000000000;
let sum = 0;
let then = performance.now();
for (let i = 0; i < numOperations; ++i) {
// calling performance.now is slow
// so only check every 1000 iterations
if (i && i % 1000 === 0) {
const now = performance.now();
// have 0.1 second elapsed?
if (now - then > 100) {
await oneMoment();
then = performance.now();
}
}
sum += doSomeOperation(i);
}
console.log(sum);
}
main();
function doSomeOperation(v) {
return v * 1.1 / (v + 1);
}
function oneMoment() {
return new Promise(resolve => setTimeout(resolve));
}
Update:
I heard a rumor the time restraints on setTimeout
might be removed because you can work around them by posting a message to yourself via postMessage
.
You still have the same issue that postMessage does take some amount of time but it's generally microseconds or less.
const pause = (function() {
let reqId = 0;
const reqs = new Map();
window.addEventListener('message', (e) => {
const resolve = reqs.get(e.data);
if (resolve) {
reqs.delete(e.data);
resolve();
}
});
return _ => new Promise(resolve => {
const id = reqId++;
reqs.set(id, resolve);
window.postMessage(id);
});
})();
async function main() {
const numOperations = 1000000000;
const iterationsPerChunk = 10000;
const startTime = performance.now();
let sum = 0;
for (let i = 0; i < numOperations; ++i) {
if (i && i % iterationsPerChunk === 0) {
await pause();
}
sum += doSomeOperation(i);
}
const elapsedTime = performance.now() - startTime;
console.log(sum);
console.log(`elapsedTime: ${(elapsedTime * 0.001).toFixed(2)}seconds`);
}
main();
function doSomeOperation(v) {
return v * 1.1 / (v + 1);
}
function oneMoment() {
return new Promise(resolve => setTimeout(resolve));
}
You can use a loop variable, like the following code. In this example, the function increases every element by 1. The timeout period is 1 millisecond.
var currentIndex;
function processNthElement(array) {
if (currentIndex >= array.length)
{
//the whole array has been processed, do what you need to do
//with the results here
return;
}
//do what you want with the array element here
array[currentIndex]++;
currentIndex++;
setTimeout(function () {
processNthElement(array);
}, 1);
}
function processArrayWithSetTimeout(array) {
currentIndex = 0;
processNthElement(array);
}
Then to process a large array, just call processArrayWithSetTimeout(array). However since we are using timeout, you need to process the result at the very last function call(see the ment in the function). If an array has 10000 elements, it will take more than 10000 milliseconds or 10 seconds to process, but the UI won't be freezed.
Note that this still processes the array sequentially but without freezing the UI as it waits for a while after processing 1 element.
Javascript is asingle thread engine. so large putation will temporary block all other event. You can use Web worker to run such big scripts in the background
You can use recursion, declare setTimeout
as a variable to be able to "break" recursive call to function which calls setTimeout()
var curr, fn = (arr, i = -1, n = arr[++i]) =>
curr = setTimeout(() => {
// do stuf with `n`: current index in `arr` array
console.log(n);
// recursively call `fn` if condition met; e.g.,
// `i` less than `arr.length`
i < arr.length ? fn(arr, i) : (curr = void 0)
}, 0);
// e.g.
fn(Array(10000).fill(1));
// clear timeout, stop recursion
clearTimeout(curr);
本文标签:
版权声明:本文标题:jquery - How to process the big loop without freezing the browser using setTimeOut function in javascript? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744005710a2574660.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论