考虑我想将一个元素的所有后代的tagName放入一个数组中。
var node = document.getElementById('mainbar');
然而,由于我们使用下面的函数循环遍历许多节点,因此我在每50个循环后添加了一个 setTimeout 函数来对函数进行超时。
function MyFunction(root){
"use strict";
var myarray = [], descendants, descendant, i=1, l;
descendants = root.getElementsByTagName('*');
function getParentNode(){
for(l = descendants.length; i<l ; i++){
descendant = descendants[i];
myarray.push({ tagName: descendant.tagName});
// After 50 loops, increment i, setTimeout
if(i % 50 == 0 ) {
i++;
setTimeout(getParentNode, 20);
}
}
}
function init(){
getParentNode();
return JSON.stringify({ nodes:myarray });
}
return init();
}
然而,有两个问题:
我该如何解决?我的意思是我已经使用了setTimeout,因此页面不会无响应。
P.S。:你可以在Stackoverflow上测试脚本,因为它包含一个带有id主栏的元素。 我同意获取Tagname不会花这么长时间,但我也在计算其他一些东西,比如每个元素的过滤getComputedStyle,这肯定需要花费很多时间。我把这个问题作为概念的证明,以了解如何使用setTimeout防止脚本响应
答案 0 :(得分:3)
忽略其他人提到的所有其他问题,只回答如何完成异步功能的问题。您可以在代码中引入回调的想法。而不是在调用之后立即尝试使用结果,而是在结果准备好后传递要调用的函数:
function MyFunction(root, callback) {
/* ... */
function getParentNode() {
for (l = descendants.length; i < l; i++) {
/* ... */
if (i % 50 == 0) {
i++;
setTimeout(getParentNode, 20);
return;
}
}
// made it out of the loop, must be done
var result = JSON.stringify({
nodes: myarray
});
callback(result);
}
getParentNode();
}
var result = MyFunction(document.getElementById("root"), function(result){
alert("GOT RESULT: " + result);
});
答案 1 :(得分:2)
这里有几个问题:
您仍然希望在getParentNode
中致电init
后,您的结果将在下一行。你不会。它还没有建成。
基本上与一个相同:MyFunction
返回init
的结果将不起作用,因为init
计划异步处理并在完成之前返回。
在getParentNode
中,您正在为getParentNode
列表中的每个节点循环并安排对descendants
的新调用。你不是异步处理它们,而是一次又安排了大量的回调。
getElementsByTagName
返回的列表始于1
,而不是0
。
如果这需要异步,您需要重构getParentNode
以便每次调用处理一个元素。
但即使是一个非常深层嵌套的结构,你也不太可能需要异步执行此操作,即使在大型文档上也不应该花费那么长时间:
function MyFunction(root) {
"use strict";
var myarray,
descendants,
i,
l;
descendants = root.getElementsByTagName('*');
myarray = [];
for (i = 0, l = descendants.length; i < l; i++) {
myarray.push({
tagName: descendants[i].tagName
});
}
return JSON.stringify(myarray);
}