是否可以在 JavaScript 中链接 setTimeout 函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6921275/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to chain setTimeout functions in JavaScript?
提问by xiatica
Is it possible to chain setTimout
functions to ensure they run after one another?
是否可以链接setTimout
功能以确保它们一个接一个运行?
回答by jfriend00
Three separate approaches listed here:
这里列出了三种不同的方法:
- Manually nest
setTimeout()
callbacks. - Use a chainable timer object.
- Wrap
setTimeout()
in a promise and chain promises.
- 手动嵌套
setTimeout()
回调。 - 使用可链接的计时器对象。
- 包裹
setTimeout()
在承诺和链承诺中。
Manually Nest setTimeout callbacks
手动嵌套 setTimeout 回调
Of course. When the first one fires, just set the next one.
当然。当第一个触发时,只需设置下一个。
setTimeout(function() {
// do something
setTimeout(function() {
// do second thing
}, 1000);
}, 1000);
Chainable Timer Object
可链接的定时器对象
You can also make yourself a little utility object that will let you literally chain things which would let you chain calls like this:
您还可以让自己成为一个小实用程序对象,它可以让您真正链接事物,让您可以像这样链接调用:
delay(fn1, 400).delay(fn2, 500).delay(fn3, 800);
function delay(fn, t) {
// private instance variables
var queue = [], self, timer;
function schedule(fn, t) {
timer = setTimeout(function() {
timer = null;
fn();
if (queue.length) {
var item = queue.shift();
schedule(item.fn, item.t);
}
}, t);
}
self = {
delay: function(fn, t) {
// if already queuing things or running a timer,
// then just add to the queue
if (queue.length || timer) {
queue.push({fn: fn, t: t});
} else {
// no queue or timer yet, so schedule the timer
schedule(fn, t);
}
return self;
},
cancel: function() {
clearTimeout(timer);
queue = [];
return self;
}
};
return self.delay(fn, t);
}
function log(args) {
var str = "";
for (var i = 0; i < arguments.length; i++) {
if (typeof arguments[i] === "object") {
str += JSON.stringify(arguments[i]);
} else {
str += arguments[i];
}
}
var div = document.createElement("div");
div.innerHTML = str;
var target = log.id ? document.getElementById(log.id) : document.body;
target.appendChild(div);
}
function log1() {
log("Message 1");
}
function log2() {
log("Message 2");
}
function log3() {
log("Message 3");
}
var d = delay(log1, 500)
.delay(log2, 700)
.delay(log3, 600)
Wrap setTimeout in a Promise and Chain Promises
将 setTimeout 包装在 Promise 和 Chain Promise 中
Or, since it's now the age of promises in ES6+, here's similar code using promises where we let the promise infrastructure do the queuing and sequencing for us. You can end up with a usage like this:
或者,由于现在是 ES6+ 中 promise 的时代,这里是使用 promise 的类似代码,我们让 promise 基础设施为我们进行排队和排序。您最终可以使用这样的用法:
Promise.delay(fn1, 500).delay(fn2, 700).delay(fn3, 600);
Here's the code behind that:
这是背后的代码:
// utility function for returning a promise that resolves after a delay
function delay(t) {
return new Promise(function (resolve) {
setTimeout(resolve, t);
});
}
Promise.delay = function (fn, t) {
// fn is an optional argument
if (!t) {
t = fn;
fn = function () {};
}
return delay(t).then(fn);
}
Promise.prototype.delay = function (fn, t) {
// return chained promise
return this.then(function () {
return Promise.delay(fn, t);
});
}
function log(args) {
var str = "";
for (var i = 0; i < arguments.length; i++) {
if (typeof arguments[i] === "object") {
str += JSON.stringify(arguments[i]);
} else {
str += arguments[i];
}
}
var div = document.createElement("div");
div.innerHTML = str;
var target = log.id ? document.getElementById(log.id) : document.body;
target.appendChild(div);
}
function log1() {
log("Message 1");
}
function log2() {
log("Message 2");
}
function log3() {
log("Message 3");
}
Promise.delay(log1, 500).delay(log2, 700).delay(log3, 600);
The functions you supply to this version can either by synchonrous or asynchronous (returning a promise).
你提供给这个版本的函数可以是同步的,也可以是异步的(返回一个承诺)。
回答by Adam Miles Crockett
If your using Typescript targeting ES6 this is pretty simple with Async Await. This is also very very easy to read and a little upgrade to the promises answer.
如果您使用面向 ES6 的 Typescript,这对于 Async Await 来说非常简单。这也非常易于阅读,并且对 promises 答案进行了一些升级。
//WARNING: this is Typescript source code
//expect to be async
async function timePush(...arr){
function delay(t){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve();
},t)
})
}
//for the length of this array run a delay
//then log, you could always use a callback here
for(let i of arr){
//pass the items delay to delay function
await delay(i.time);
console.log(i.text)
}
}
timePush(
{time:1000,text:'hey'},
{time:5000,text:'you'},
{time:1000,text:'guys'}
);
回答by Kenji
I have encountered the same issue. My solution was to call self by setTimeout
, it works.
我遇到了同样的问题。我的解决方案是通过调用 self setTimeout
,它有效。
let a = [[20,1000],[25,5000],[30,2000],[35,4000]];
function test(){
let b = a.shift();
console.log(b[0]);
if(a.length == 0) return;
setTimeout(test,b[1]);
}
the second element in array a is time to be delayed
数组 a 中的第二个元素是要延迟的时间
回答by Penny Liu
Inspired by @jfriend00I demonstrated a shorter version:
受到@jfriend00 的启发,我展示了一个较短的版本:
Promise.resolve()
.then(() => delay(400))
.then(() => log1())
.then(() => delay(500))
.then(() => log2())
.then(() => delay(800))
.then(() => log3());
function delay(duration) {
return new Promise((resolve) => {
setTimeout(() => resolve(), duration);
});
}
function log1() {
console.log("Message 1");
}
function log2() {
console.log("Message 2");
}
function log3() {
console.log("Message 3");
}