Javascript foreach循环转到回调上的下一个元素

时间:2011-11-17 20:07:08

标签: javascript

for(var P in ReturnData.Playlist){
    var IsLoaded = false;
    if(PlayerName == "A"){
        LoadNavA(false,false,false, ReturnData.Playlist[P], function(){
            IsLoaded = true;
            alert();
        });
        }else{
        LoadNavB(false,false,false, ReturnData.Playlist[P],function(){
            IsLoaded = true;
        });
    }
    if(IsLoaded == true) continue;
}

这适用于音乐播出系统。 LoadNavALoadNavB函数异步加载轨道到播放列表。这些元素必须按正确的顺序排列。当轨道3比轨道2更早加载时,它首先放置轨道3而不是轨道2,但是当轨道1和2已经加载时它应该开始加载轨道3。

当调用LoadNavALoadNavB中的回调时,循环应该继续。怎么样?

1 个答案:

答案 0 :(得分:1)

您遇到的问题是LoadNavALoadNavB调用异步操作,这些操作可以按任何顺序返回,但您尝试强制执行某些排序。这是一个问题,因为你的循环将在回调实际执行时完成,所以你试图阻止处理是错误的。

相反,您想要的是按顺序调用某些异步操作的方法。我写了一个通用函数来完成这个:

// receives a callback and the elements to iterate
function loop(list, fn) {
    if (!list || list.length <= 0)
        return;
    (function chain(i) {
        if (i >= list.length)
            return;
        fn(list[i], function() {
            chain(i + 1);
        });
    })(0);
} 

此函数假设您正在为其提供一个将执行某些操作的回调,并且该操作将在链完成后启动链中的下一步。为了使这个具体,这里有一个基于你的代码的例子。

首先,进行一些设置,以便我们可以使用您的示例:

var PlayerName = "B";
var ReturnData = {};
ReturnData.Playlist = ["song1", "song2", "song3"];

function LoadNavA(b1, b2, b3, el, fn) {
    // this could be any asynchronous call (e.g. Ajax)
    // using setTimeout here for illustration
    window.setTimeout(fn, 2000);
}

var LoadNavB = LoadNavA; // for brevity

现在,loop的实际使用情况:

loop(ReturnData.Playlist, function(song, next) {
    if (PlayerName == "A") {
        LoadNavA(false, false, false, song, function() {
            alert("LoadNavA: " + song);
            next();
        });
    } else {
        LoadNavB(false, false, false, song, function() {
            alert("LoadNavB: " + song);
            next();
        });
    }

});

作为loop的第二个参数给出的回调将对列表中的每个元素执行一次。它接收播放列表中的元素和称为next的函数作为参数。只要这些操作在完成后调用next函数,该回调就可以自由执行任何异步操作。这是我们前进到播放列表中下一个元素的机制,以便可以为每个元素重复该过程。