Ist eine Verkettung möglich setTimout
Funktionen, um sicherzustellen, dass sie nacheinander ablaufen?
Ist es möglich, setTimeout-Funktionen in JavaScript zu verketten?
xiatica
jfriend00
Hier sind drei separate Ansätze aufgeführt:
- Manuell verschachteln
setTimeout()
Rückrufe. - Verwenden Sie ein verkettbares Timer-Objekt.
- Wickeln
setTimeout()
in einem Versprechen und Kettenversprechen.
SetTimeout-Callbacks manuell verschachteln
Natürlich. Wenn der erste feuert, stellen Sie einfach den nächsten ein.
setTimeout(function() {
// do something
setTimeout(function() {
// do second thing
}, 1000);
}, 1000);
Verkettbares Timer-Objekt
Sie können sich auch ein kleines Hilfsobjekt erstellen, mit dem Sie Dinge buchstäblich verketten können, mit denen Sie Aufrufe wie folgt verketten können:
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)
Packen Sie setTimeout in ein Promise und verketten Sie Promises
Oder, da es jetzt das Zeitalter der Versprechungen in ES6+ ist, hier ist ein ähnlicher Code, der Versprechungen verwendet, wobei wir die Versprechungsinfrastruktur das Einreihen und Sequenzieren für uns erledigen lassen. Sie können mit einer Verwendung wie dieser enden:
Promise.delay(fn1, 500).delay(fn2, 700).delay(fn3, 600);
Hier ist der Code dahinter:
// utility function for returning a promise that resolves after a delay
function delay
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
}
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);
Die Funktionen, die Sie dieser Version bereitstellen, können entweder synchron oder asynchron sein (Zurückgeben eines Versprechens).
-
Ich entschuldige mich für meine dummen Fragen, aber gibt es Internetbrowser, die Javascript-Funktionen gleichzeitig verarbeiten (einschließlich Mobilgeräte), und wenn ja, stellt dies sicher, dass sie nicht gleichzeitig ausgeführt werden?
– xiatica
4. August 2011 um 1:53 Uhr
-
Das gesamte Browser-Javascript ist Single-Threaded. Es wird immer nur ein Ausführungsthread ausgeführt, sodass sequentielle Anweisungen immer nacheinander ausgeführt werden. Zwei Teile von Javascript laufen NIEMALS gleichzeitig.
– jfriend00
4. August 2011 um 2:02 Uhr
-
Ein verkettbares Timer-Objekt mit Warteschlangen und einer Cancel-Methode hinzugefügt.
– jfriend00
11. Februar 2016 um 22:46 Uhr
-
Kann das fn-Argument von delay eine Funktion sein, die ein Argument wie function logMessage(message) { log(message); }? Und wenn ja, wie könnte ich das Nachrichtenargument übergeben?
– Ebbraun
9. Juni 2016 um 6:26 Uhr
-
Danke, bind ist süß und funktioniert. Für alle Interessierten hier jsfiddle.net/efbbrown/ypa25gsc/1 So können Sie Eingaben an das fn-Argument binden.
– Ebbraun
9. Juni 2016 um 8:30 Uhr
Inspiriert von @jfriend00 habe ich eine kürzere Version demonstriert:
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");
}
Wenn Sie Typescript für ES6 verwenden, ist dies mit Async Await ziemlich einfach. Dies ist auch sehr sehr einfach zu lesen und ein kleines Upgrade auf die Antwortversprechen.
//WARNING: this is Typescript source code
//expect to be async
async function timePush(...arr){
function delay
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'}
);
Kenji
Ich bin auf das gleiche Problem gestoßen. Meine Lösung war, sich selbst anzurufen setTimeout
Es klappt.
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]);
}
das zweite Element in Array a ist die zu verzögernde Zeit
Verwenden async / await
mit @Penny Liu Beispiel:
(async() => {
await delay(400)
log1()
await delay(500)
log2()
await delay(800)
log3()
})()
async 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");
}