简体   繁体   中英

Build list of time delayed function calls within loop

I'm trying to make a list of function calls separated by a timed interval. The code below currently takes the last item for each function call.

The current code prints: itemThree, itemThree, itemThree - each separated by ten seconds

The desired code prints: itemOne, itemTwo, itemThree - each separated by ten seconds

//Declare variables
var itemList = ["itemOne", "itemTwo", "itemThree"];
var timerInterval = 0;

//Loop through the itemList and build a list of functions calls
//Each function call will be lined up with a 10 second gap
for(index = 0; index < itemList.length; index++) {
    var item = itemList[index]; 
    setTimeout(function() { doSomethingWithItem(item); }, timerInterval);
    timerInterval = timerInterval + 10000;
}

//Print passed in item 
var doSomethingWithItem = function(item) {
    console.log(item);
}

I'm trying to make a list of timer delayed function calls. How would I need to change the above code, or is there a better solution? Thanks for yours helps.

JavaScript passes values by reference , and by the time timeout fires, index will reach its greatest value and therefore "itemThree" will always be shown. To fix that, you need to create another scope for the looping variable to live in so it doesn't get changed by outer scope.

//Loop through the itemList and build a list of functions calls
//Each function call will be lined up with a 10 second gap
for(index = 0; index < itemList.length; index++) {
    // creating new scope for index to live in
    (function(num) {
        var item = itemList[num]; 
        setTimeout(function() { doSomethingWithItem(item); }, timerInterval);
        timerInterval = timerInterval + 10000;
    })(index);
}

An approach I use in cases like this is to use an immediately invoked function expression in a pseudo-recursive loop to extract the elements from the list one at a time:

//Declare variables
var itemList = ["itemOne", "itemTwo", "itemThree"];
var timerInterval = 10000;

(function loop() {
    var item = itemList.shift();
    if (item) {
        setTimeout(function() {
            doSomethingWithItem(item);
            loop()
        }, timerInterval);
    }
})();

//Print passed in item 
var doSomethingWithItem = function(item) {
    console.log(item);
}

Without the for loop you avoid the issue of the item variable having its last assigned value during each callback.

With the pseudo-recursive use of setTimeout you also avoid queuing more than one timer at a time. I call this usage pseudo-recursive because whilst it may appear that loop is calling itself, in reality the setTimeout call merely adds callbacks to a queue of functions to be triggered from the browser's event processing loop.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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