考虑以下javascript算法:
for(var i = 0; i < 50; i ++){
console.log('starting :', i);
getPrimes(1000000);
(function(i){
setTimeout(function(){
console.log('done :', i);
}, 1000);
})(i);
}
function getPrimes(max) {
var sieve = [], i, j, primes = [];
for (i = 2; i <= max; ++i) {
if (!sieve[i]) {
// i has not been marked -- it is prime
primes.push(i);
for (j = i << 1; j <= max; j += i) {
sieve[j] = true;
}
}
}
return primes;
}
for循环启动getPrimes函数需要一些时间,然后运行另一个超时为1秒的函数。考虑到这个算法,我期望在控制台上得到的是&#34;开始&#34;和&#34;完成&#34;从开始到结束排序的行,但不一定从1到50排序。
实际上我得到的是50行&#34;开始&#34; (这需要一些时间来处理)然后不断完成50行&#34;完成&#34;。
我的问题是为什么?逻辑告诉我在运行for循环时至少应该完成一个timout回调,因为javascript是单线程异步,它应该显示一行&#34; done&#34;介于&#34;开始&#34;
的某些行之间可能是因为素数计算需要所有的CPU功率吗?
由于
答案 0 :(得分:3)
问题出在javascrypt events数组中,所以所有超时函数运行都进入数组,javascript虚拟机在for循环完成运行后运行它们。为了更好地理解,ypu可以运行以下代码:
for( var i=0; i<10; i++) {
console.log(i);
setTimeout(function(){
console.log('hhh');
},0)
}
因此输出将是setTimeout之前的所有console.logs,然后是所有setTimeout的console.log。
当我们调用setTimeout时,超时事件会排队。然后继续执行: 运行setTimeout调用后的行,然后是之后的行,依此类推, 直到没有线路为止。只有这样才能生成JavaScript虚拟机 问,“队列里有什么?” 如果队列中至少有一个事件有资格“开火”(如500ms 在1000ms前设置的超时),VM将选择一个并调用其处理程序 (例如,我们传递给setTimeout的函数)。当处理程序返回时,我们 回到队列。 输入事件的工作方式相同:当用户使用a单击DOM元素时 单击处理程序附加,单击事件排队。但处理程序不会 执行直到所有当前正在运行的代码完成(并且可能直到 在其他事件发生之后)。这就是使用Java-的网页的原因 脚本不明智地往往没有反应。
在你的具体问题中,他们一起被解雇只是因为你把它们全部放在“事件数组”中,所以他们所有人的时间都相同,你等待的时间就是你在setTimeout中设置的时间+计算时间的较小增量。
在Angular中进行编程时,我使用它来确保我的代码在完成任何其他操作之后运行,因此我只是将setTimeout()放在没有时间值的情况下,并且内部代码在其他所有内容之后执行。
答案 1 :(得分:0)
Javascript不是多线程的:代码将继续执行,直到它返回主循环。
答案 2 :(得分:0)
循环发生50次,显示开始
然后在每个循环中,代码(function(){})();
在读取后立即执行,因为它是自我调用!
但setTimeout
将在for
循环
for-loop timer: timer started
"starting :" 0
selfinvokingfunction timer: timer started
selfinvokingfunction timer: 0ms
"starting :" 1
selfinvokingfunction timer: timer started
selfinvokingfunction timer: 0ms
"starting :" 2
selfinvokingfunction timer: timer started
selfinvokingfunction timer: 0ms
for-loop timer: 656ms
setTimeout timer: timer started
"done :" 0
setTimeout timer: 0ms
setTimeout timer: timer started
"done :" 1
setTimeout timer: 0ms
setTimeout timer: timer started
"done :" 2
setTimeout timer: 0ms
使用console.time
和console.timeEnd
来检查执行顺序相同的时间,for
循环是否以秒结束。