美元.进入循环:为什么函数在递增之后执行
$.get in a loop: why the function is performed after incrementing?
我是Javascript的初学者,我觉得我对$有一些问题。jQuery。
通常,您可以将其分配给一个函数,该函数将在正确检索数据后执行。
但是如果我把$。进入一个循环,循环继续执行,即使数据还没有被检索到,这就是我的问题。
下面是我的代码(这是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。例如,如果它应该返回1,则返回长度事件。
我试着在url声明之后放一个警告(I),我明白i++是在我的$.get中的函数之前完成的。
这当然是一个微不足道的问题,但我无法理解不让这种情况发生的逻辑
这样包装您的$.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
来处理下一个元素。
由于使用的是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 );
}
});
});
对原始代码的修改如下:
- jQuery调用代替
getElementsBy*
函数 jQuery - 添加了缺少
var
的地方。(在任何版本的代码中都非常重要!)
.each()
for the loop.注意,使用.each()
自动提供与另一个答案中立即调用的函数表达式(IIFE)相同的效果,但没有额外的复杂性。这是因为.each()
总是使用回调函数,并且创建了闭包,以便在每次循环迭代中唯一地保留i
变量(以及element
)。
当你有一个普通的while
或for
循环时,你也可以这样做,你仍然不需要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时,请尝试将该代码分解成一个完全独立的函数。在许多情况下,它会导致代码更具可读性。
这里有一个小演示供您进一步研究。
$("#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
输出(浏览器挂起5558ms!):
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
- 如何在`window.open`之后执行回调
- 在$state.go之后执行$window.location.reload(true)
- Javascript:在每个onmouseover事件之后执行2个函数
- 可以使 jquery 点击事件在所有其他点击事件之后执行
- 在两个元素的 onrender 事件之后执行函数
- 流星技术/模式,用于等待数据库变量更改,然后在 in 之后执行某些操作
- 在jQuery .load Ajax之后执行if-statement
- 使javascript在firefox中的插件javascript之后执行
- 在catch之后执行
- 是否可以在特定的console.log()条目之后执行Javascript函数
- oncomplete 方法并不总是在操作 JSF 之后执行
- nodejs:setImmediate 回调在 setTimeout(fn, 0) 之后执行,与 nodejs 文档描述
- 为什么我不能在我的OnclientClickEvent之后执行我的onClick
- 在 ajax 之后执行数据表或重新绘制表
- 在 jQuery / Javascript 中的 bind() 事件之后执行条件
- 如何使 jQuery 语句在 .load() 之后执行
- 在具有 FS 操作的 FOR 循环之后执行
- 在 dgrid renderRow 之后执行一个函数
- window.print() 之后的 Javascript 有时在打印对话框之前执行,有时在打印对话框之后执行
- 在 3SE 之后执行函数