如何 运行 多个定时器功能,一个接一个地在香草 javascript
How to run multiple timer functions, one after the other in vanilla javascript
假设我想要 运行 多个计时器功能,一个接一个,即首先一个功能 运行s 持续 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
您必须等待第一个调用结束才能进行第二个调用。一个简单的方法是用 Promise
包装 setInterval
调用,并在计数器达到 0 时调用 resolve
。
使用 Promise(ES6 但在大多数浏览器上运行,IE 需要 Polyfill)
timer(15).then(timer.bind(0, 5));
function timer(count) {
console.log(count);
return new Promise(function(resolve) {
var intervalID = setInterval(function() {
count = count - 1;
if (count < 0) {
clearInterval(intervalID);
resolve();
return;
}
console.log(count);
}, 1000);
});
}
使用 async
和 await
(ES7)
(async function() {
await timer(15);
await timer(5);
})();
async function timer(count) {
console.log(count);
return new Promise(resolve => {
let intervalID = setInterval(() => {
count = count - 1;
if (count < 0) return resolve(), clearInterval(intervalID);
console.log(count);
}, 1000);
});
}
在现代 javascript 中处理异步内容的最佳方式是 promises 和 async/await
。但是因为wait
没有默认的方式我们需要自己写。这很简单:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
现在我们可以用它来写你的 timer
和 async/await
并使它 return 成为 Promise
:
async function timer(count) {
for(let i = count; i > 0; i--) {
await wait(1000);
console.log(i);
}
}
而且在异步函数中多次使用 timer
并不容易:
await timer(15);
await timer(5);
所以完整的代码是:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
async function timer(count) {
for(let i = count; i > 0; i--) {
await wait(1000);
console.log(i);
}
}
async function multipleTimers() {
await timer(15);
await timer(5);
}
multipleTimers();
您似乎希望第二个 timer
函数仅在第一个函数的所有间隔都完成时才执行。这绝对不是你实施的。实际上,第一个函数被调用,它设置了时间间隔,然后结束。主代码不会被间隔的设置打断,所以它会继续执行,调用第二个timer
函数。
根据您想要的输出,您肯定需要一个异步函数,以了解第一个间隔何时执行完毕。以下是您可以尝试的方法:
function timer(count) {
return new Promise(resolve => {
console.log(count)
let counter = setInterval(() => {
count = count - 1;
if (count < 0) {
clearInterval(counter);
resolve();
return;
}
console.log(count)
}, 1000);
}
}
timer(15).then(() => {
timer(5);
});
如果你已经在一个异步函数中,最后一位也可以写成:
await timer(15);
timer(5);
你应该阅读一下 async functions。真的很值得。
问题是您的 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)))));
承诺
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 提供帮助的一件事是回调地狱,现在如果你想 运行 定时器 5,然后是 4,然后是 3,然后是 2,然后是 1,你会得到很多更合理的代码:
timer(5)
.then(() => timer(4))
.then(() => timer(3))
.then(() => timer(2))
.then(() => timer(1));
不再嵌套。
async/await
这其实又是Promises。而是带着伪装。如果一个函数 returns 一个 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();
假设我想要 运行 多个计时器功能,一个接一个,即首先一个功能 运行s 持续 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
您必须等待第一个调用结束才能进行第二个调用。一个简单的方法是用 Promise
包装 setInterval
调用,并在计数器达到 0 时调用 resolve
。
使用 Promise(ES6 但在大多数浏览器上运行,IE 需要 Polyfill)
timer(15).then(timer.bind(0, 5));
function timer(count) {
console.log(count);
return new Promise(function(resolve) {
var intervalID = setInterval(function() {
count = count - 1;
if (count < 0) {
clearInterval(intervalID);
resolve();
return;
}
console.log(count);
}, 1000);
});
}
使用 async
和 await
(ES7)
(async function() {
await timer(15);
await timer(5);
})();
async function timer(count) {
console.log(count);
return new Promise(resolve => {
let intervalID = setInterval(() => {
count = count - 1;
if (count < 0) return resolve(), clearInterval(intervalID);
console.log(count);
}, 1000);
});
}
在现代 javascript 中处理异步内容的最佳方式是 promises 和 async/await
。但是因为wait
没有默认的方式我们需要自己写。这很简单:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
现在我们可以用它来写你的 timer
和 async/await
并使它 return 成为 Promise
:
async function timer(count) {
for(let i = count; i > 0; i--) {
await wait(1000);
console.log(i);
}
}
而且在异步函数中多次使用 timer
并不容易:
await timer(15);
await timer(5);
所以完整的代码是:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
async function timer(count) {
for(let i = count; i > 0; i--) {
await wait(1000);
console.log(i);
}
}
async function multipleTimers() {
await timer(15);
await timer(5);
}
multipleTimers();
您似乎希望第二个 timer
函数仅在第一个函数的所有间隔都完成时才执行。这绝对不是你实施的。实际上,第一个函数被调用,它设置了时间间隔,然后结束。主代码不会被间隔的设置打断,所以它会继续执行,调用第二个timer
函数。
根据您想要的输出,您肯定需要一个异步函数,以了解第一个间隔何时执行完毕。以下是您可以尝试的方法:
function timer(count) {
return new Promise(resolve => {
console.log(count)
let counter = setInterval(() => {
count = count - 1;
if (count < 0) {
clearInterval(counter);
resolve();
return;
}
console.log(count)
}, 1000);
}
}
timer(15).then(() => {
timer(5);
});
如果你已经在一个异步函数中,最后一位也可以写成:
await timer(15);
timer(5);
你应该阅读一下 async functions。真的很值得。
问题是您的 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)))));
承诺
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 提供帮助的一件事是回调地狱,现在如果你想 运行 定时器 5,然后是 4,然后是 3,然后是 2,然后是 1,你会得到很多更合理的代码:
timer(5)
.then(() => timer(4))
.then(() => timer(3))
.then(() => timer(2))
.then(() => timer(1));
不再嵌套。
async/await
这其实又是Promises。而是带着伪装。如果一个函数 returns 一个 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();