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

时间:2017-12-14 08:03:56

标签: javascript html typescript settimeout

我需要使用多个参数多次调用一个函数。我希望在上一次调用的超时完成后调用它。我尝试了以下方法,但它似乎没有正常工作。 (Here's the JSFiddle)。

现在它只在第一次通话后等待。我知道这不是正确的方法,但我找不到任何正确显示如何做的例子。我还需要将其转换为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>

注意:

函数call()仅用于表示目的。参数可以有任何值,函数myFunction()可以随时随地调用。

4 个答案:

答案 0 :(得分:3)

由于这个问题用typescript标记,我会认为在Typescript中写这个是一个选项。

您可以使用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!");

}

注意:如果您不想要打字稿,babel也支持async/await,但您仍需要转发器。

注意要使用es5async/await进行编译,如果环境中没有承诺,则需要Priomise库,并且您可以使用流动的tconfig.json:

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

纯js方法可以使用onDone回调来通知调用者该函数何时真正完成。最好直接在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);
}

答案 1 :(得分: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>

答案 2 :(得分:0)

尝试这种模式

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

答案 3 :(得分:0)

实际上,执行它并不是一个好方法,但在这种情况下,你不能连续调用myFunction函数,因为setTimeout运行异步并且不阻塞线程。所以,像这样修改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);

}

Call函数看起来像;

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