嵌套的setTimeout替代?

时间:2013-07-10 15:20:48

标签: javascript

我需要在1秒钟内执行3个功能。

为简单起见,这些功能是:

console.log('1');
console.log('2');
console.log('3');

我能做到这一点:(非常难看)

 console.log('1')
 setTimeout(function () {
     setTimeout(function () {
         console.log('2')
         setTimeout(function () {
             console.log('3')

         }, 1000)
     }, 1000)

 }, 1000)

或者我可以创建array个函数,并将setIntervalglobal计数器一起使用。

有没有优雅的方式吗?

(p.s。函数2不依赖于函数编号1 ...因此 - 每秒执行下一个函数。)。

6 个答案:

答案 0 :(得分:13)

您可以使用setTimeout

来使用此类内容
var funcs = [func1, func2, func3],
    i = 0;

function callFuncs() {
    funcs[i++]();
    if (i < funcs.length) setTimeout(callFuncs, 1000);
}
setTimeout(callFuncs, 1000); //delay start 1 sec.

或者直接调用callFuncs()开始。

<强>更新

setInterval方法(注意堆叠通话的风险):

var funcs = [func1, func2, func3],
    i = 0,
    timer = setInterval(callFuncs, 1000);

function callFuncs() {
    funcs[i++]();
    if (i === funcs.length) clearInterval(timer);
}

答案 1 :(得分:9)

假设您在现代浏览器上运行它或添加了对array.map的支持,这非常简洁:

[func1, func2, func3].map(function (fun, index) {
    setTimeout(fun, 1000 + index * 1000);
}

答案 2 :(得分:3)

setTimeout(function(){console.log('1')}, 1000);
setTimeout(function(){console.log('2')}, 2000);
setTimeout(function(){console.log('3')}, 3000);

答案 3 :(得分:1)

我认为最简单的方法是在函数中创建一些闭包 首先我要回忆一下,你对使用setInterval很感兴趣,因为setTimeout的开销可能会触发10毫秒的目标。因此,特别是如果使用短(<50ms)间隔,则更喜欢setInterval。 所以我们需要存储函数数组,最新执行函数的索引以及停止调用的间隔引用。

function chainLaunch(funcArray, time_ms) {
  if (!funcArray || !funcArray.length) return;
  var fi = 0; // function index
  var callFunction = function () {
      funcArray[fi++]();
      if (fi==funcArray.length)
              clearInterval(chainInterval);
   } ;
  var chainInterval = setInterval( callFunction, time_ms);
}

Rq:你可能想要复制函数数组(funcArray = funcArray.slice(0);
Rq2:你可能想在数组中循环
Rq3:你可能想接受chainlaunch的附加参数。使用var funcArgs = arguments.slice(3);检索它们并在函数上使用apply:funcArray[fi++].apply(this,funcArgs);

无论如何,以下测试有效:

var f1 = function() { console.log('1'); };
var f2 = function() { console.log('2'); };
var f3 = function() { console.log('3'); };

var fArr = [f1, f2, f3];

chainLaunch(fArr, 1000);

正如你在这个小提琴中看到的那样:http://jsfiddle.net/F9UJv/1/ (打开控制台)

答案 4 :(得分:1)

在es6中有一种称为生成器的新类型的函数声明(a.k.a ecmascript 6,es2015)。它对这种情况非常有用,并使您的异步代码看起来是同步的。 es6是2015年最新的JavaScript标准。它适用于现代浏览器,但您现在可以使用Babel及其javascript polyfill来使用生成器,即使在较旧的浏览器上也是如此。

Here是关于生成器的教程。

下面的函数myDelayedMessages是一个生成器的示例。 Run是一个辅助函数,它接受一个它调用的生成器函数,并提供一个函数来推动生成器作为它调用的生成器函数的第一个参数。

function delay(time, callback) {
      setTimeout(function () {
        callback();
      }, time);
}

function run(generatorFunction) {
  var generatorItr = generatorFunction(resume);
  function resume(callbackValue) {
    generatorItr.next(callbackValue);
  }
  generatorItr.next()
}

run(function* myDelayedMessages(resume) {
  for(var i = 1; i <= 3; ++i) {
    yield delay(1000, resume);
    console.log(i);
  }
});

这是代码的概述,类似于上面教程的最终概述。

  1. run接受我们的生成器并创建一个恢复功能。运行创建一个 生成器 - 迭代器对象(接下来调用的东西),提供 恢复。
  2. 然后它将生成器 - 迭代器推进一步 一切都关闭。
  3. 我们的生成器遇到第一个yield语句 并呼叫延迟。
  4. 然后发电机暂停。
  5. 延迟完成1000毫秒后调用resume。
  6. resume告诉我们的发电机推进一步。
  7. 我们的发生器继续从它产生的地方继续,然后是console.logs i,这是1,然后继续循环
  8. 我们的发电机遇到第二次产量调用, 呼叫延迟并再次暂停。
  9. 延迟等待1000毫秒,最终 调用简历回调。恢复再次推进发电机。
  10. 我们的发电机从它产生的地点继续,然后是console.logs i,即2,然后继续循环。
  11. 延迟等待1000毫秒,最终 调用简历回调。恢复再次推进发电机。
  12. 我们的发生器继续从它产生的地方继续,然后是console.logs i,这是3,然后继续并且循环结束。
  13. 没有更多的屈服,生成器完成执行。

答案 5 :(得分:0)

这里有两种方法。一个是setTimeout,另一个是setInterval。在我看来,第一个更好。

for(var i = 1; i++; i<=3) {
  setTimeout(function() {
      console.log(i);
    }, 1000*i);
}
// second choice:
var i = 0;
var nt = setInterval(function() {
      if(i == 0) return i++;
      console.log(i++);
      if(i>=3) clearInterval(nt);
    }, 1000);