代码之家  ›  专栏  ›  技术社区  ›  Sanju

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

  •  3
  • Sanju  · 技术社区  · 6 年前

    我需要使用多个参数多次调用函数。我希望在上一次调用超时后调用它。我试过下面的方法,但它似乎不能正常工作。( 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 回复  |  直到 6 年前
        1
  •  4
  •   Titian Cernicova-Dragomir    6 年前

    因为这个问题标有 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!");
    
    }
    

    笔记 :如果你不想要typescript,babel还支持 异步/等待 但你仍然需要一个transpiler。

    笔记 编译的目的 es5 具有 异步/等待 你需要一个 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);
    }
    
        2
  •  2
  •   amir gorji    6 年前

    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>
        3
  •  0
  •   Emre Kabaoglu    6 年前

    实际上,执行它不是一种好方法,但在这种情况下,您无法调用 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);
    
    }
    

    调用函数如下所示;

    function call(){
       myFunction('normal1','heading1','message1'); //Just call first function in the beginning
    }
    
        4
  •  0
  •   Fan Cheung    6 年前

    试试这个图案

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