【问题标题】:Async behaviour in javascript [duplicate]javascript中的异步行为[重复]
【发布时间】:2014-07-03 18:44:49
【问题描述】:

考虑以下 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 到 50 排序的“开始”和“完成”行之间的混合。

实际上,我得到的是 50 行“开始”(需要一些时间来处理),然后是 50 行“完成”。

我的问题是为什么?逻辑告诉在运行 for 循环时,至少应该完成一个 timout 回调,并且因为 javascript 是单线程异步的,它应该在一些“starting”行之间显示一行“done”

可能是因为素数计算占用了所有cpu功率?

谢谢

【问题讨论】:

  • Could it be because the primes calculation takes all the cpu power? 在任务管理器里找就行了。
  • ´setTimeout´ 并不是“在 x 毫秒后运行”,而是“在 x 毫秒后运行,但前提是 CPU 准备就绪”。 Javascript 永远不会在同步代码块的中间运行 setTimeout。

标签: javascript


【解决方案1】:

问题出在 javascrypt 事件数组中,因此所有超时函数运行都进入数组,并且 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 虚拟机 问:“队列上有什么?” 如果队列中至少有一个事件可以“触发”(例如 500 毫秒) 1000 毫秒前设置的超时),VM 将选择一个并调用其处理程序 (例如,我们传递给 setTimeout 的函数)。当处理程序返回时,我们 回到队列中。 输入事件的工作方式相同:当用户单击带有 单击处理程序附加,单击事件排队。但处理程序不会 执行,直到所有当前正在运行的代码完成(并且,可能,直到 在其他事件轮到他们之后)。这就是为什么使用 Java 的网页- 脚本轻率地倾向于变得反应迟钝。

在您的特定问题中,它们被一起解雇只是因为您将它们一起放入“事件数组”中,因此它们的时间对所有这些都几乎相同,而您之前等待的时间就是您在 setTimeout 中设置的时间+计算时间的小增量。

在 Angular 中编程时,我使用它来确保我的代码在其他任何事情完成后运行,所以我只是将 setTimeout() 放在没有时间值的情况下,并且内部代码在其他所有事情之后立即执行。

【讨论】:

    【解决方案2】:

    循环发生 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.timeconsole.timeEnd 来检查执行顺序是否相同,for 循环是否在一秒钟内完成。

    【讨论】:

      【解决方案3】:

      Javascript 不是多线程的:代码会继续执行,直到返回主循环。

      【讨论】:

        猜你喜欢
        • 2017-10-22
        • 1970-01-01
        • 2017-09-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-26
        • 1970-01-01
        • 2016-12-06
        相关资源
        最近更新 更多