javascript - 如何在vanilla javascript中一个接一个地运行多个计时器函数

标签 javascript setinterval

假设我想运行多个计时器函数,一个接着一个,即首先一个函数运行 5 分钟,然后在第一个倒计时完成后,另一个计时器开始再运行 2 分钟。

我实现了定时器功能如下

function timer(count) {
    console.log(count)
    let counter = setInterval(() => {
        count = count - 1;
        if (count < 0) {
            clearInterval(counter);
            return;
        }
        console.log(count)
    }, 1000);
}

然后当我使用不同的参数调用这个函数两次时

timer(15);
timer(5);

我得到的输出为

15
5
14
4
13
3
11
1
10
0
9
8
.
.
0

但是我想要的输出是

15
14
.
.
2
1
0
5
4
3
2
1
0

最佳答案

问题是您的timer函数立即启动计时器。计时器是异步的,因此当您调用它两次时,您只需立即启动两个计时器并且它们并行运行。

如果您希望在完成后发生某些事情,那么您必须明确地说出来。您有两个选择:

回调

这是处理异步代码的稍微“旧”的风格。您调用一个稍后执行某些操作的函数,然后为其提供一个函数作为参数,指示完成后要执行的操作:

function timer(count, callback = () => {}) { //<-- take callback
 //if callback is not supplied, it's going to be an empty function
       
    console.log(count)
    let counter = setInterval(() => {
        count = count - 1;
        if (count < 0) {
            clearInterval(counter);
            callback(); //<-- run callback after this timer is finished
            return;
        }
        console.log(count)
    }, 1000);
}

//run a timer for 15 then a timer for 5
timer(15, () => timer(5));

有效,但过度使用回调可能会导致所谓的 callback hell 。这里的例子也很容易出现这种情况,例如,如果您想运行一个计时器 5,然后是 4,然后是 3,然后是 2,然后是 1,您最终会得到这样的结果:

timer(5, 
  () => timer(4, 
    () => timer(3, 
      () => timer(2, 
        () => timer(1)
      )
    ) 
  )
);

或者一行(为了好玩):

timer(5, () => timer(4, () => timer(3, () => timer(2, () => timer(1)))));

promise

Promises是处理异步操作的更新方法,有助于保持代码简洁。

function timer(count) {
  console.log(count)

  return new Promise(resolve => { //return a Promise
    let counter = setInterval(() => {
      count = count - 1;
      if (count < 0) {
        clearInterval(counter);
        resolve(); //it is resolved when the count finishes
        return;
      }
      console.log(count)
    }, 1000);
  });
}

//run a timer for 15 then a timer for 5
timer(15)
  .then(() => timer(5));

Promises 帮助解决的一件事是回调 hell ,现在如果你想运行一个计时器 5,然后是 4,然后是 3,然后是 2,然后是 1,你会得到一个更合理的代码:

timer(5)
  .then(() => timer(4))
  .then(() => timer(3))
  .then(() => timer(2))
  .then(() => timer(1));

不再嵌套。

异步/等待

这实际上又是Promise。不过是乔装打扮而已。如果函数返回 Promise,您可以 await 它等待 Promise 被解析,然后执行下一行代码。您只能在 async 函数中使用 await,但是,由于 await 实际上在幕后将您的代码转换为 Promise。从功能上讲,没有什么区别,但您可以以不同的方式构建代码:

function timer(count) {
  console.log(count)

  return new Promise(resolve => { //return a Promise
    let counter = setInterval(() => {
      count = count - 1;
      if (count < 0) {
        clearInterval(counter);
        resolve(); //it is resolved when the count finishes
        return;
      }
      console.log(count)
    }, 1000);
  });
}

//run a timer for 15 then a timer for 5
async function main() { //you can only use `await` in async funcions 
  await timer(15);
  await timer(5);
}
/* the above will actually be transformed behind the scenes into:
timer(15)
  .then(() => timer(5));
*/

main();

关于javascript - 如何在vanilla javascript中一个接一个地运行多个计时器函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59628791/

相关文章:

javascript - jQuery :contain multiple selection

javascript - 访问不存在的图像 URL 是否会影响 Web 服务器?

javascript - useState 中没有 () 的函数( react 钩子(Hook))

reactjs - 使用 sinon.fakeTimers 测试 setInterval() 不起作用?

javascript - Canvas 中随时间变化的颜色(js)/setInterval 的问题

javascript - SetInterval不会停止运行

javascript - 迭代动态创建的嵌套数组

JavaScript,我正在发出 ajax 请求,我需要帮助浏览该对象

javascript - 如何使用setInterval直到图像未加载?

javascript - 使用 snap svg 的发光效果