13

我需要在 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计数器一起使用。

有什么 优雅的方法吗?

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

4

7 回答 7

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);
}
于 2013-07-10T15:27:35.407 回答
10

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

[func1, func2, func3].map(function (fun, index) {
    setTimeout(fun, 1000 + index * 1000);
}
于 2013-07-10T15:37:37.310 回答
8
setTimeout(function(){console.log('1')}, 1000);
setTimeout(function(){console.log('2')}, 2000);
setTimeout(function(){console.log('3')}, 3000);
于 2013-07-10T15:33:08.790 回答
3

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

是关于生成器的教程。

下面的函数 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获取我们的生成器并创建一个恢复函数。run 创建一个生成器迭代器对象(你接下来调用的东西),提供简历。
  2. 然后它将生成器迭代器推进一步以启动所有内容。
  3. 我们的生成器遇到第一个 yield 语句并调用 delay。
  4. 然后生成器暂停。
  5. 延迟在 1000 毫秒后完成并调用 resume。
  6. resume 告诉我们的生成器前进一步。
  7. 我们的生成器从它在console.logs i产生的位置继续,即1,然后继续循环
  8. 我们的生成器遇到第二次对 yield 的调用,调用 delay 并再次暂停。
  9. delay 等待 1000ms 并最终调用 resume 回调。resume 再次使生成器前进。
  10. 我们的生成器从它在console.logs i(即2)产生的位置继续,然后继续循环。
  11. delay 等待 1000ms 并最终调用 resume 回调。resume 再次使生成器前进。
  12. 我们的生成器从它在console.logs i 处产生的位置继续,即3,然后继续,循环结束。
  13. 不再调用 yield,生成器完成执行。
于 2015-10-08T20:58:35.487 回答
1

我认为最简单的方法是在函数中创建一些闭包。
首先,我会记得您对 using 非常感兴趣setInterval,因为它的开销setTimeout可能会触发 10ms 偏离目标。所以特别是如果使用短(<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:您可能想要接受链启动的附加参数。检索它们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/ (打开控制台)

于 2013-07-10T16:05:25.567 回答
1

使用异步/等待

const pause = _ => new Promise(resolve => setTimeout(resolve, _));

async function main() {
  await pause(1000);
  console.log('one');
  
  await pause(1000);
  console.log('two');
  
  await pause(1000);
  console.log('three');
}

main();

请注意,这也可以循环使用

const pause = _ => new Promise(resolve => setTimeout(resolve, _));

async function main() {
  for (let i = 0; i < 3; ++i) {
    await pause(1000);
    console.log(i + 1);
  }
}

main();

于 2021-09-21T17:09:34.090 回答
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);

于 2015-03-18T04:41:45.363 回答