簡體   English   中英

用setTimeout遞歸調用函數

[英]Calling a function recursively with setTimeout

我想用setTimeout遞歸地調用幾個函數。

var flag = 0 ;
function slave1(){
    if(flag < 60) {
        var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT1"); // Checking if DOM has loaded or not. If yes then doing something.
        if (COPY_PO_LINE_DIV != null) {
            flag = 0;
            //doing something
        } else { 
            setTimeout(slave1,2000); //waiting for 2 seconds and checking again.
        }
    }
}

//doing similar task
function slave2(){
    if(flag < 60) {
        var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT2");              
        if (COPY_PO_LINE_DIV != null) {
            flag = 0;
            //doing something
        } else {
            setTimeout(slave2,2000);
        }
    }
}

function master() {
    slave1();
    console.log("Without completing slave1 function.");
    slave2();
}

我想通過master()函數一個接一個地調用多個函數,但是在當前情況下,它調用slave2()而不完成slave1() 我如何確保slave1()已執行完畢。 如果未加載DOM元素,則它應每2秒執行60次,然后應從slave1()取出並轉到下一個。

如果不加載dom元素而不將控件返回到下一個功能,我想執行60次相同的功能。

您需要調整slave1以在完成后運行回調,該回調將為slave2

function slave1(callback){
    if(flag < 60) {
        var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT1"); // Checking if DOM has loaded or not. If yes then doing something.
        if (COPY_PO_LINE_DIV != null) {
            flag = 0;
            //doing something
            callback();
        } else { 
            setTimeout(slave1,2000); //waiting for 2 seconds and checking again.
        }
    }
}

function slave2(){...}

function master() {
    slave1(slave2);
    console.log("Without completing slave1 function.");
}

這是您的基本javascript鏈接。 如果您有更多的奴隸,您可能想研究async.series否則您會進入回調地獄,因為Gabs00很好地指出了這一點:

slave1(function(){
    slave2(function(){
        slave3(function(){
            slave4(slave5);
        });
    });
});

如果您需要將值傳遞給回調函數,則需要使用一個中間匿名函數,該函數進而使用相關參數調用預期的回調函數。 為此,您需要定義函數,以便它們使用參數:

function slave1(str, callback){...}
function slave3(i, callback){...}

slave1("some argument", function(){
    slave2("another argument", function(){
        slave3(1, function(){
            slave4(2, slave5);
        });
    });
});

考慮對此類事情使用諾言。 在此基於jQuery的實現,其他promise庫的工作方式與此類似。

function waitForElement(elementId, maxTries, checkInterval) {
    var d = $.Deferred(), intvalID, checkFunc;

    // set up default values
    maxTries = maxTries || 60;
    checkInterval = checkInterval || 2000;

    checkFunc = function () {
        var elem = document.getElementById(elementId);
        if (maxTries-- > 0 && elem) {
            clearInterval(intvalID);
            d.resolve(elem);
        }
        if (maxTries <= 0) {
            clearInterval(intvalID);
            d.reject(elementId);
        }
    };

    // set up periodic check & do first check right-away
    intvalID = setInterval(checkFunc, checkInterval);
    checkFunc();

    return d.promise();
}

現在,如果要一個接一個地測試元素,則可以像這樣級聯調用:

function master() {
    waitForElement("DOM_ELEMENT1").done(function (elem1) {
        waitForElement("DOM_ELEMENT2").done(function (elem2) {
            alert("elem1 and elem2 exist!");
            // now do something with elem1 and elem2
        }).fail(function () {
            alert("elem1 exists, but elem2 was not found.");
        });
    }).fail(function () {
        alert("elem1 not found.");
    });
}

或者您可以並行執行此操作,並在所有元素都存在時調用回調:

function master() {
    $.when(
        waitForElement("DOM_ELEMENT1"),
        waitForElement("DOM_ELEMENT2")
    )
    .done(function (elem1, elem2) {
        alert("elem1 and elem2 exist!");
        // now do something with elem1 and elem2 
    })
    .fail(function () {
        alert("not all elements were found before the timeout");
    });
}

您的slave2函數應作為回調傳遞給slave1函數,並應在它完成后在slave1調用(如果有的話?)。 您的當前情況非常普遍,因為setTimeout()函數是異步的,因此JS解釋器不會等到函數完成后才在Evet循環的末尾設置setTimeout()結果並繼續處理master()方法。

為了將參數傳遞給函數,創建匿名函數實在是太過分了。 考慮改為使用“綁定”。 所以,如果你有

function slave1(str, callback){...}
function slave2(str, callback){...}
function slave3(i, callback){...}
function slave4(i, callback){...}
function slave5()

而不是使用

slave1("some argument", function(){
    slave2("another argument", function(){
        slave3(1, function(){
            slave4(2, slave5);
        });
    });
});

考慮使用

slave1("some argument", 
    slave2.bind(null, "another argument",
        slave3.bind(null, 1,
            slave4.bind(null, 2, slave5)
        )
    )
);

就內存和CPU利用率而言,要容易得多,效率更高。 現在,如何使用setTimeout做到這一點:

slave1("some argument",
    setTimeout.bind(null, slave2.bind(null, "another argument",
        setTimeout.bind(null, slave3.bind(null, 1,
            setTimeout.bind(null, slave4.bind(null, 2,
                setTimeout.bind(null, slave5, 0)
            ),0)
        ),0)
    ),0)
);

我在http://morethanslightly.com/index.php/2014/09/executables-the-standard-solution-aka-mind-the-bind/上更詳細地解釋了該問題

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM