【问题标题】:How to wait for setTimeout before each function call?如何在每个函数调用之前等待 setTimeout?
【发布时间】:2018-05-28 06:12:32
【问题描述】:

我需要使用多个参数多次调用一个函数。我希望在上一次调用的超时完成后调用它。我尝试了以下方法,但似乎无法正常工作。 (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()可以随时随地调用。

【问题讨论】:

  • 制作一个循环.. 您现在只使用 1 个函数,这会在再次遍历整个循环之间产生延迟。你现在的函数是,1(等待 3 秒)1-2(等待 3 秒)1-2-3
  • 不要从call函数调用myFunction三次。从那里只调用一次,另外两次从alertFunc 函数中的setTimeout 回调调用(换句话说,使用递归)。
  • @Titus @Tomm 函数call() 仅用于表示。可以有任意数量的对myFunction() 的调用。我想将此功能导入另一个项目。

标签: javascript html typescript settimeout


【解决方案1】:

由于这个问题标有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 也支持async/await,但你仍然需要一个转译器。

注意要编译 es5async/await,如果环境中没有 Promise,则需要一个 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);
}

【讨论】:

  • Async-Await 仅在面向 ECMAScript 2015 或更高版本时受支持。我们正在使用 es5。
  • @SanjuAus 不正确,不记得何时添加了对 es5 的支持,但它在那里,您可能需要一个 promise 库,但您可以定位 es5
  • 但我收到错误,TS1311: Async functions are only available when targeting ECMAScript 2015 or higher.
  • 检查你的ts版本
  • @SanjuAus 还加了一个JS版本,不过我还是说TSasync/await看起来好多了:)
【解决方案2】:

试试这个模式

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

【讨论】:

    【解决方案3】:

    实际上,执行它不是很好的方法,但是在这种情况下,您不能连续调用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
    }
    

    【讨论】:

    • 正如我在评论中提到的,函数 call() 仅用于表示目的。参数可以有任何值。
    【解决方案4】:

    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>

    【讨论】:

    • 消息数组未知时如何实现?
    • 按摩数组必须在第一次调用方法之前定义,并且可以在处理过程中改变,甚至超时调用它检查小于按摩长度的全局i变量;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    • 2016-06-04
    相关资源
    最近更新 更多