简体   繁体   English

如何在每次函数调用之前等待setTimeout?

[英]How to wait for setTimeout before each function call?

I need to call a function multiple times with multiple parameters. 我需要使用多个参数多次调用一个函数。 I want it to be called after the timeout of the previous call is completed. 我希望在上一次调用的超时完成后调用它。 I've tried the following method but it doesn't seem to be working correctly. 我尝试了以下方法,但它似乎没有正常工作。 ( Here's the JSFiddle ). 这是JSFiddle )。

Right now it is only waiting after first call. 现在它只是在第一次通话后等待。 I know it's not the correct way to do this, but I could not find any examples that correctly showed how to do. 我知道这不是正确的方法,但我找不到任何正确显示如何做的例子。 I will also need to convert it to typescript , so please consider that while answering. 我还需要将其转换为typescript ,所以请在回答时考虑一下。

<!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>

Note: 注意:

The function call() is just for representation purposes. 函数call()仅用于表示目的。 The parameters can have any value and the function myFunction() can be called anytime, anywhere. 参数可以具有任何值,并且可以随时随地调用函数myFunction()。

Since this question is marked with typescript I'm going to asume that writing this in Typescript is an option. 由于这个问题用typescript标记,我打算假设在Typescript中写这个是一个选项。

You could use async/await to easily achieve the effect you want while your code maintains a normal look: 在代码保持正常外观时,您可以使用async/await轻松实现所需的效果:

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!");

}

Note : If you don't want typescript, babel also has support for async/await but you will still need a transpiler. 注意 :如果你不想要打字稿,babel也支持async/await但是你仍然需要一个转换器。

Note To compile for es5 with async/await you will need a Priomise library if promises aren't in the environment, and you can use the flowing tconfig.json: 注意要使用async/await编译es5 ,如果promises不在环境中,则需要Priomise库,并且可以使用流动的tconfig.json:

"compilerOptions": {
    "target": "es5",
    "lib": [
        "es5",
        "es2015.promise",
        "dom"
    ]
}

A pure js approach could use an onDone callback to have a way to notify the caller of when the function really completed. 纯js方法可以使用onDone回调来通知调用者函数何时真正完成。 This is better that to add the code directly in alertFunc as other answers suggest as that will make alertFunc less reusable: 这更好的是直接在alertFunc添加代码,因为其他答案建议,因为这将使alertFunc不再可重用:

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);
}

 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> 

try this pattern 尝试这种模式

function callMe(yourParam){
//you can conditionly modify your param 
//if (somecondition)
// newParam=yourPram ... 
setTimeout(()=>callMe(newParam),1000)
}

Actually, it is not nice approach to perform it but in this case, you couldn't call myFunction function consecutively because setTimeout runs asynchronous and don't block the thread. 实际上,执行它并不是一个好方法,但在这种情况下,你不能连续调用myFunction函数,因为setTimeout运行异步并且不阻塞线程。 So, modify alertFunc like this; 所以,像这样修改alertFunc ;

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(){
            if(msgType == "normal1")
            {
                 myFunction('normal2','heading2','message2');//Call second function after first one completed
            }
            if(msgType == "normal2")
            {
                 myFunction('normal3','heading3','message3');//Call third function after second one completed
            }
        x.className = x.className.replace("show", "");
        alert("Should display "+heading+" "+message+" now!");
    }, 3000);

}

And the Call function looks like; Call函数看起来像;

function call(){
   myFunction('normal1','heading1','message1'); //Just call first function in the beginning
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM