setTimeout() 如何在 JS 上工作

How is setTimeout() working on JS

本文关键字:JS 工作 setTimeout      更新时间:2023-09-26

Just Learn JS.在我看来,函数 setTimeout 代码区域应该像正常一样工作,但事实并非如此:

var result = 0;
(function (i){
if(i > 0){
    result = result + i;
    i = i - 1;
    setTimeout("arguments.callee(" + i + ")",100);//arguments.callee(i);
}
else if(i == 0)
    return;
}(10));
alert(result);

我希望它提醒 55 而不是 10,如果删除设置超时,它会很好。有人知道为什么吗?

尝试

var result = 0;
(function (i, callback) {
    if (i > 0) {
        result = result + i;
        i = i - 1;
        var callee = arguments.callee;
        setTimeout(function () {
            callee(i, callback)
        }, 100);
    } else if (i == 0) {
        callback();
    }
}(10, function () {
    alert(result);
}));

演示:小提琴

为什么?
您的方法存在多个问题

  1. setTimeout 是异步的,这意味着您的警报将在添加操作完成之前触发 - 解决方案是使用回调方法,该方法将在添加结束后执行,如上所示
  2. 当您将字符串传递给setTimeout它将在全局范围内执行时,即arguments.callee将引用与您期望的不同对象。

因为setTimeout异步的,简单来说,这意味着它计划稍后执行。JS不会等待它(不会在该行停止代码),而是运行后续代码。

因此,当您稍后设置它时,代码会继续超出"超时循环"并进入警报。在此期间,循环只做了一个周期,result只增加了 10 个。

您可以执行的操作:

  • 您可以在"超时循环"结束时设置警报
  • 或者,您可以发送一个函数,即在循环完成后执行的"回调"。
  • arguments.callee已弃用。您可以命名您的 IIFE 并让超时调用它

鉴于:

  1. arguments.callee 不受欢迎(并且不推荐使用)
  2. 命名函数表达式有其自身的问题
  3. 这里似乎有一个目标,即不创建全局变量来运行超时

考虑在 IIFE 中声明函数(根据我认为您想要的内容进行调整 - 10 次迭代后显示结果为 10 的警报):

var result = 0;
(function (i){
  function foo(j) {
    if(j > 0){
      ++result;
      setTimeout(function(){foo(--j)},100);
    } else {
      alert('Result: ' + result);
    }
  }
  foo(i);
}(10));

请注意,不需要 else 块(除非您想返回 undefined 以外的内容)。

哦,请注意,在 ES5 和其他支持它的浏览器(不是 IE <9)中,您可以在调用 setTimeout 时传递参数:

  setTimeout(foo, 100, --j);

因此,您保存了一个额外的函数对象。