数组被覆盖

时间:2015-10-22 19:19:22

标签: javascript jquery arrays

后台:我有一个函数,它接受一组本地链接字符串,加载每个链接并从每个链接中的特定位置查找所有<a>标记,然后推送每个将href属性标记为名为results的数组。

问题:函数运行完毕后,结果数组为空。如果我在console.log函数内部使用.load()测试数组的长度或内容,则数组具有内容,正如我所期望的那样;但是,在该函数之外,数组是空的。

假设:我认为填充的数组会以某种方式被空数组覆盖,但我无法看到它是如何发生的。我甚至尝试将结果数组放在main函数之外,作为全局变量,但在函数执行后它仍然是空的。

功能

function collectAllTrailLinks(arrayOfSections){
   var result = [];
   var len = arrayOfSections.length;
   $("body").append("<div id='placeHolder'></div>");

   for (var i = 0; i < len; i++) {
      var params = arrayOfSections[i] + " " + "blockquote a";
      $("#placeHolder").load(params, function(){
        $("#placeHolder a").each(function(){
            var link = $(this).attr("href");
            if (link !== "symbols.html") {
                result.push(link);
            }
         });
     }); 
   }
   console.log(result.length);
   //return result;
}

功能调用

function ctRunAll(){
  createTable("#ctSection h1", 16);
  var sectionLinks = collectLinks(hikingContent);
  collectAllTrailLinks(sectionLinks[0]);
}

1 个答案:

答案 0 :(得分:4)

那是因为传递给$("#placeHolder").load()的回调函数是异步执行的。这意味着函数collectAllTrailLinks()在第一次调用该回调之前已经完成。

您可以做的是返回一个承诺,这样您就可以等到所有负载完成。我创建了一个代码片段,演示了原生的Promise方式(使用setTimeout而不是$.load进行了简化)

var output = document.getElementById('output');

function collectAllTrailLinks() {
    var promises = [];
    for (var i = 0; i < 20; i++) {
        var promise = new Promise(function(resolve, reject) {
            var index = i;
            setTimeout(function() {
                output.innerHTML += 'finished ' + index + ' ';
            	resolve('result of ' + index);
        	}, i * 200);
        });
        promises.push(promise);
    }
    return Promise.all(promises);
}

collectAllTrailLinks().then(function (result) {
    output.innerHTML += '<br /><br />All done: ' + JSON.stringify(result);
});
<div id="output"></div>

JQuery延迟方式

function collectAllTrailLinks(arrayOfSections) {
   var defer = $.Deferred();
   var result = [];
   var len = arrayOfSections.length;
   var finishedLoads = 0;
   $("body").append("<div id='placeHolder'></div>");

   for (var i = 0; i < len; i++) {
      var params = arrayOfSections[i] + " " + "blockquote a";
      $("#placeHolder").load(params, function(){
        $("#placeHolder a").each(function(){
            var link = $(this).attr("href");
            if (link !== "symbols.html") {
                result.push(link);
            }
         });
         finishedLoads++;
         if (finishedLoads == len) {
             defer.done(result); // mark deferred as done (will resolve promise)
         }
     }); 
   }
   return defer.promise(); // return promise where you can wait on
}

// Usage (wait for promise)
collectAllTrailLinks(arrayOfSections).done(function(result) {
   console.log(result.length);
});

原生承诺方式

function collectAllTrailLinks(arrayOfSections) {
   var promises = [];

   $("body").append("<div id='placeHolder'></div>");

   for (var i = 0; i < arrayOfSections.length; i++) {
       var promise = new Promise(function(resolve, reject) {
          var params = arrayOfSections[i] + " " + "blockquote a";
          $("#placeHolder").load(params, function(response, status, xhr) {
             if (status === "error") {
                 return reject(response);
             }

             var result = [];
             $("#placeHolder a").each(function() {
                var link = $(this).attr("href");
                if (link !== "symbols.html") {
                   result.push(link);
                }
             });

             resolve(result);
          });
       });
       promises.push(promise);
   }

   return Promise.all(promises);
}

// Usage
collectAllTrailLinks(arrayOfSections).then(function(results) {
   console.log(results.length);
});