循环中的jquery延迟进行顺序处理

时间:2015-04-29 19:14:54

标签: jquery

目标:循环遍历一段时间的网址,让他们使用postMessage完全加载以确定何时完成(某些页面需要很长时间)

实现了这一点,但它的工作不正常:jquery deferred in for loop

实现了这个,并且它正在工作,但不在循环中,因为javascript只打开最后一个窗口:http://davidwalsh.name/window-postmessage

function scrape(url){
    var deferred = new $.Deferred();
      var myPopUp = window.open(url,'myWindow');
      setInterval(function(){
        var message = 'Hello!  The time is: ' + (new Date().getTime());
        console.log('Scraper Launcher:  sending message:  ' + message);
        myPopUp.postMessage(message,domain);//send the message and target URI
        },6000);

        //listen to holla back
        window.addEventListener('message',function(event) {
                if(event.origin !== domain) return;
                console.log('received response:  ',event.data);
                if(event.data == 'You were successful!'){
                   console.log('closing child window');
                   myPopUp.close();
                   deferred.resolve('Success');
                }else{
                   console.log('oh dear, FAILURE: ' + urls[i]);
                   deferred.resolve('Failure');
                }
             },false);


    return deferred.promise();
}

    var urls = [domain +"/url1",domain +"/url2"];

   $("#launch_windows").click(function(){
      console.log('launching');
      for (i = 0; i < urls.length; i++) {
         (function(i){
            console.log('NOW i is ' + i + ' and url is ' + urls[i]);
            $.when(scrape(urls[i])).then(function(results){
               console.log('DONE (' + results + ')with ' + urls[i]);
            });
          })(i);
      }
    });

如果这是完全可怕的逻辑和代码,我很乐意接受建议。

1 个答案:

答案 0 :(得分:7)

我喜欢通过创建解析的$ .Deferred,添加到链,并在每次迭代时将延迟的值分配给新的promise来解决这些问题(异步操作的顺序循环)。

$("#launch_windows").click(function(){
    console.log("launching");
    var dfd = $.Deferred().resolve();
    for(i = 0; i < urls.length; i++){
        (function(i){
            dfd = dfd.then(function(){
                return scrape(urls[i]);
            }).then(function(results){
                console.log("results: "+results);
            });
        })(i);
    }
});

使用forEach而非IIFE提供封闭的清洁版:

var dfd = $.Deferred().resolve();
urls.forEach(function(url){
    dfd = dfd.then(function(){
        return scrape(url);
    }).then(function(results){
        console.log("results: "+results);
    });
});

您的问题在每次迭代中都在$.when中。在第一次迭代$.when创建了一个新的promise(由于scrape返回一个promise而不必要的btw),然后添加了一个then来处理结果。在下一次迭代中,未引用此原始承诺,并为下一个url创建新的承诺(在第一次完成刮擦之前!)等等。

此解决方案将所有异步操作保存在同一个$ .Deferred链中,按顺序执行它们(您想要的)。

你确实得到使用IIFE来冻结i值的分数!

继承人jsFiddle