0

我是 Javascript 的初学者,我觉得 $.get jQuery 有问题。

通常,您可以将其分配给将在正确检索数据后执行的函数。

但是,如果我将 $.get 放入循环中,即使尚未检索到数据,循环也会继续执行,这就是我的问题。

这是我的代码(这是给 GreaseMonkey 的):

var1 = document.getElementsByClassName("some_class");
i = 0;

while (i < var1.length) {
    url = var1[i].getElementsByTagName("some_tag")[0].href;

    $.get(url, function(data) {
        if (data.contains("some_string")) {
            alert(i);
        }
    });
i++;
}

此处,警报返回 var1.length 事件,如果它应该返回 1 为例。

我尝试在 url 声明之后放置一个 alert(i),我知道 i++ 是在我的 $.get 中的函数之前完成的。

这肯定是一个微不足道的问题,但我无法掌握不发生这种情况的逻辑。

4

3 回答 3

2

包装你的$.get功能:

(function(i) {
    $.get(url, function(data) {
        if (data.contains("some_string")) {
            alert(i);
        }
    });
})(i);

立即调用的函数表达式导致外部范围内的当前值i通过函数的参数绑定i(然后隐藏外部变量)。如果你愿意,可以给函数参数一个不同的名字。

请注意,这仅解决了您实际陈述的问题,即循环变量独立于回调而递增。如果您希望确保 AJAX 请求一次运行一个,那么还有其他解决方案,例如:

var els = document.getElementsByClassName("some_class");
var i = 0;

(function loop() {
    if (i < els.length) {
        var el = els[i];
        var url = el.getElementsByTagName("some_tag")[0].href;
        $.get(url).done(function(data) {
            if (data.contains("some_string")) {
                alert(i);
            }
            i++;
        }, loop);   // .done(f1, f2) - see below
     }
})();

.done()调用形式为,.done(callback, loop)两个函数会依次调用。所以这i++条线总是首先发生,然后它安排loop被伪递归地调用以处理下一个元素。

于 2013-04-27T16:06:54.680 回答
1

由于您使用的是 jQuery,因此您可以大大简化代码:

$('.some_class').each( function( i, element ) {
    var url = $(element).find('some_tag')[0].href;
    $.get( url, function( data ) {
        if( data.contains("some_string") ) {
            alert( i );
        }
    });
});

对原始代码的更改是:

  1. jQuery 调用而不是getElementsBy*函数。
  2. .each()用于循环的jQuery 。
  3. var在需要的地方添加了缺失。(在任何版本的代码中都非常重要!)

请注意,使用.each()自动为您提供与另一个答案中立即调用的函数表达式(IIFE)相同的效果,但没有额外的复杂性。那是因为.each()总是使用回调函数,并且创建了为循环的每次迭代唯一地保留i变量(也是)所需的闭包。element

当你有一个普通的whilefor循环时,你也可以这样做,但你仍然不需要 IIFE。相反,只需在循环中调用一个函数。以这种方式编写,代码将是:

var $elements = $('.some_class');
for( var i = 0;  i < $elements.length;  i++ ) {
    checkElement( i, $elements[i] );
}

function checkElement( i, element ) {
    var url = $(element).find('some_tag')[0].href;
    $.get( url, function( data ) {
        if( data.contains("some_string") ) {
            alert( i );
        }
    });
}

如您所见,该checkElement函数与.each()回调函数相同。实际上,.each()只需为您运行一个类似的for循环并以与此代码完全相同的方式调用回调。此外,for循环比循环更具可读性,while因为它将所有循环变量操作放在一个地方。(如果你不熟悉for循环语法,起初它可能看起来不太可读,但一旦你习惯了它,你可能会发现你更喜欢for循环。)

通常,当想在循环中间使用 IIFE 时,请尝试将代码拆分成一个完全独立的函数。在许多情况下,它会导致代码更具可读性。

于 2013-04-27T16:41:18.673 回答
0

这是一个小演示,供您进一步研究。

$("#output").empty();

var startTime = new Date().getTime();

// try experimenting with async = true/false and the delay
// don't set async to false with too big a delay,
// and too high a count,
// or you could hang your browser for a while!
// When async==false, you will see each callback respond in order, followed by "Loop finished".
// When async==true, you could see anything, in any order.
var async = true;
var delay = 1;
var count = 5;

function createClosure(i) {
    // return a function that can 'see' i.
    // and i's remains pinned within this closure
    return function (resp) {
        var duration = new Date().getTime() - startTime;
        $("#output").append("\n" + i + " returned: " + resp + " after " + duration + "ms");
    };
}

for (var i = 0; i < count; i++) {
    // jsfiddle url and params
    var url = "/echo/html/";
    var data = {
        html: "hello " + i,
        delay: delay
    };

    $.ajax(url, {
        type: "post",
        data: data,
        async: async
    }).then(createClosure(i));
}

var duration = new Date().getTime() - startTime;
$("#output").append("\n" + "Loop finished after " + duration + "ms");

样本async=true输出:

Loop finished after 7ms
0 returned: hello 0 after 1114ms
1 returned: hello 1 after 1196ms
2 returned: hello 2 after 1199ms
4 returned: hello 4 after 1223ms
3 returned: hello 3 after 1225ms

示例async=false输出(浏览器挂起 5558 毫秒!):

0 returned: hello 0 after 1113ms
1 returned: hello 1 after 2224ms
2 returned: hello 2 after 3329ms
3 returned: hello 3 after 4444ms
4 returned: hello 4 after 5558ms
Loop finished after 5558ms
于 2013-04-27T16:23:13.543 回答