javascript - Hur man väntar på setTimeout innan varje funktionsanrop?
Jag behöver anropa en funktion flera gånger med flera parametrar. Jag vill att den anropas efter att timeouten för det föregående anropet har slutförts. Jag har försökt följande metod men det verkar inte fungera korrekt. (Här är JSFiddle).
Just nu väntar det bara efter det första samtalet. Jag vet att det inte är rätt sätt att göra detta, men jag kunde inte hitta några exempel som korrekt visade hur man gör. Jag kommer också behöva konvertera det till typescript, så vänligen ta hänsyn till det när du svarar.
<!DOCTYPE html>
<html>
<body>
<p>Click the button to wait 3 seconds, then alert "Hello".</p>
<button onclick="call()">Call all methods</button>
<script>
var myVar;
function call(){
myFunction('normal1','heading1','message1');
myFunction('normal2','heading2','message2');
myFunction('normal3','heading3','message3');
/*Output should be:
(first time dont wait)
heading1 message1
(then wait for timeout and remove the elements)
heading2 message2
(then wait for timeout and remove the elements)
heading3 message3
*/
}
function myFunction(msgType,heading,message) {
console.log(!!document.getElementById("snackbarParent"),document.getElementById('snackbarParent'));
if(document.getElementById("snackbarParent") == null)
{
alertFunc(msgType,heading,message);
}
else{
setTimeout(function(){
let parent = document.getElementById('snackbarParent');
parent.parentNode.removeChild(parent);
alertFunc(msgType,heading,message);
},3500);
}
}
function alertFunc(msgType,heading,message) {
let div = document.createElement('div');
div.className = 'snackbarParent';
div.id = "snackbarParent";
div.innerHTML = '<div id="snackbar"><b style="color:' + msgType + '"> ' + heading + ' </b>' + message + '</div>';
document.documentElement.appendChild(div);
// Get the snackbar DIV
let x = document.getElementById("snackbar");
// Add the "show" class to DIV
x.className = "show";
setTimeout(function(){
x.className = x.className.replace("show", "");
alert("Should display "+heading+" "+message+" now!");
}, 3000);
}
</script>
</body>
</html>
Notera:
Funktionen call() är bara för representationsändamål. Parametrarna kan ha vilket värde som helst och funktionen myFunction() kan kallas när som helst, var som helst.
Svar #1
Eftersom denna fråga är markerad med typescript kommer jag att anta att det är ett alternativ att skriva detta i Typescript.
Du kan använda async/await för att enkelt uppnå den effekt du vill ha samtidigt som din kod behåller ett normalt utseende:
var myVar;
async function call(){
await myFunction('normal1', 'heading1', 'message1');
await myFunction('normal2', 'heading2', 'message2');
await myFunction('normal3', 'heading3', 'message3');
}
function timeout(delay: number) {
return new Promise(r => setTimeout(r, delay));
}
async function myFunction(msgType: string, heading: string, message: string) {
console.log(!!document.getElementById("snackbarParent"), document.getElementById('snackbarParent'));
if (document.getElementById("snackbarParent") == null) {
await alertFunc(msgType, heading, message);
}
else {
await timeout(3500);
let parent = document.getElementById('snackbarParent');
parent.parentNode.removeChild(parent);
await alertFunc(msgType, heading, message);
}
}
async function alertFunc(msgType, heading, message) {
let div = document.createElement('div');
div.className = 'snackbarParent';
div.id = "snackbarParent";
div.innerHTML = '<div id="snackbar"><b style="color:' + msgType + '"> ' + heading + ' </b>' + message + '</div>';
document.documentElement.appendChild(div);
// Get the snackbar DIV
let x = document.getElementById("snackbar");
// Add the "show" class to DIV
x.className = "show";
await timeout(3000);
x.className = x.className.replace("show", "");
alert("Should display " + heading + " " + message + " now!");
}
Observera: Om du inte vill ha TypeScript, har Babel också stöd för async/await men du kommer fortfarande behöva en transpiler.
Obs För att kompilera för es5 med async/await behöver du ett Promise-bibliotek om promises inte finns i miljön, och du kan använda följande tconfig.json:
"compilerOptions": {
"target": "es5",
"lib": [
"es5",
"es2015.promise",
"dom"
]
}
Ett rent js-ansats skulle kunna använda en onDone-callback för att ha ett sätt att meddela anroparen när funktionen verkligen är klar. Detta är bättre än att lägga koden direkt i alertFunc som andra svar föreslår eftersom det kommer att göra alertFunc mindre återanvändbar:
function call() {
myFunction('normal1', 'heading1', 'message1', function () {
myFunction('normal2', 'heading2', 'message2', function () {
myFunction('normal3', 'heading3', 'message3', function () {
// DOne
});
});
});
}
function myFunction(msgType, heading, message, onDone) {
console.log(!!document.getElementById("snackbarParent"), document.getElementById('snackbarParent'));
if (document.getElementById("snackbarParent") == null) {
alertFunc(msgType, heading, message, onDone);
}
else {
setTimeout(function () {
var parent = document.getElementById('snackbarParent');
parent.parentNode.removeChild(parent);
alertFunc(msgType, heading, message, onDone);
}, 3500);
}
}
function alertFunc(msgType, heading, message, onDone) {
var div = document.createElement('div');
div.className = 'snackbarParent';
div.id = "snackbarParent";
div.innerHTML = '<div id="snackbar"><b style="color:' + msgType + '"> ' + heading + ' </b>' + message + '</div>';
document.documentElement.appendChild(div);
// Get the snackbar DIV
var x = document.getElementById("snackbar");
// Add the "show" class to DIV
x.className = "show";
setTimeout(function () {
x.className = x.className.replace("show", "");
alert("Should display " + heading + " " + message + " now!");
if (onDone)
onDone();
}, 3000);
}
Svar #2
var massages = [];
massages[0] = ['normal1','heading1','message1'];
massages[1] = ['normal2','heading2','message2'];
massages[2] = ['normal3','heading3','message3'];
function settime(i){
setTimeout(fn,3000,i)
}
function fn(i){
var heading = massages[i][1],
message = massages[i][2],
msgType = massages[i][0];
let x = document.getElementById("snackbar");
x.innerHTML = '<div id="snackbar"><b style="color:' + msgType + '"> ' + heading + ' </b>' + message + '</div>';
alert("Should display "+heading+" "+message+" now!");
if(i<massages.length-1) {i++;settime(i)};
}<p>Click the button to wait 3 seconds, then alert "Hello".</p>
<button onclick="settime(0)">Try it</button>
<div id='snackbar'></div>