我想对DOM进行长时间的运行,一个节点一个节点的走动,在每个节点上调用一个函数,但又不至于让浏览器无法响应。所以我想异步是最好的办法。
我觉得jQuery Deferred对象可以提供一个解决方案,但我还没能想出一个。
有谁能举个例子说明如何用jQuery(或者其他库,如果有特别适合的,或者纯Javascript和DOM方法)做到这一点。
更复杂的是,我希望能够以不同的顺序进行遍历,例如后序,但还不是需求。
你可以用setTimeout递归的方式来实现。由于Javascript是单线程的,你可以通过周期性地放弃线程来创造拥有多个线程的假象。调用setTimeout会将剩余的工作排成队列,并在继续之前处理任何未完成的事件。
下面是一个jQuery的工作示例。
function traverse(node, visitor, root) {
if (root === undefined)
root = node;
visitor(node, function() {
if (!node.length)
return;
let nextNode;
if (node.children().length) {
nextNode = node.children().first();
} else {
nextNode = node;
do {
if (root.length && nextNode.length && nextNode[0] == root[0]) {
nextNode = $();
break;
} else if (nextNode.next().length) {
nextNode = nextNode.next();
break;
} else {
nextNode = nextNode.parent();
}
} while (nextNode.length);
}
setTimeout(function() { traverse(nextNode, visitor, root); }, 200);
});
}
这将调用 visitor
与所有DOM节点进行深度优先预排序遍历,然后调用 visitor
用一个空的jQuery对象来表示它已经完成了。visitor
必须调用它的第二个参数来进行遍历。
traverse($('#rootNode'), function(node, proceed) {
if (!node.length) {
console.log('done with traversal');
// no proceed() call at the end
} else if (node.hasClass('my-class')) {
// let's say that this click triggers an AJAX request that makes a node visible later in traversal
node.trigger('click');
proceed(); // continue traversal
} else if (node.hasClass('ajax-response-container')) {
function checkIfVisible() {
if (node.is(':visible')) {
// yay, ajax response arrived
console.log('AJAX response', node.html());
// continue traversal
proceed();
} else {
// wait for ajax node to become visible
window.requestAnimationFrame(checkIfVisible);
// no proceed() call - don't continue traversal yet
}
}
checkIfVisible();
} else {
// continue traversal for any other node encountered
proceed();
}
});
如果你能使用HTML5,一些浏览器就会支持web worker。https:/developer.mozilla.orgEnUsing_web_workers。这可能是一个选择。 你也许可以把DOM作为文档传递给方法,然后从那里开始。
你可以看看 https:/github.comwilsonpagefastdom。 就是这样,在dom中进行异步操作。
你可能会想检查这个方法
https:/gist.github.comstelf4b6935071447724c7066。
基于Kris Kowal的Q库。基本上类似于SynXsiS的想法,但在PromisesDeffered对象方面结构更多一些。