Javascript 用jQuery异步遍历DOM树

Javascript 用jQuery异步遍历DOM树,javascript,jquery,dom,asynchronous,tree-traversal,Javascript,Jquery,Dom,Asynchronous,Tree Traversal,我希望对DOM执行一次长时间运行的逐节点遍历,在每个节点上调用一个函数,但不会使浏览器无响应。 所以我认为异步是一种方式 我认为jQuery延迟对象可以提供一个解决方案,但我还没有想出一个解决方案 有谁能举例说明如何使用jQuery(或者其他库,如果其中一个特别适合的话;或者纯Javascript和DOM方法)做到这一点 更复杂的是,我希望能够以不同的顺序进行遍历,例如postorder,但这还不是必需的。如果可以使用HTML5,一些浏览器支持web工作人员。 这可能是一种选择。您可以将DOM作

我希望对DOM执行一次长时间运行的逐节点遍历,在每个节点上调用一个函数,但不会使浏览器无响应。 所以我认为异步是一种方式

我认为jQuery延迟对象可以提供一个解决方案,但我还没有想出一个解决方案

有谁能举例说明如何使用jQuery(或者其他库,如果其中一个特别适合的话;或者纯Javascript和DOM方法)做到这一点


更复杂的是,我希望能够以不同的顺序进行遍历,例如postorder,但这还不是必需的。

如果可以使用HTML5,一些浏览器支持web工作人员。
这可能是一种选择。您可以将DOM作为文档传递给方法并从那里开始。

如果您可以使用HTML5,某些浏览器支持web工作者。
这可能是一种选择。您可以将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);
    });
}
这将使用所有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();
    }
});

您可以使用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);
    });
}
这将使用所有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();
    }
});

您可以查看dom中的异步操作到底是哪种操作。

您可以查看dom中的异步操作到底是哪种操作。

您可能需要检查这种方法


基于Kris Kowal的Q库。基本上与SynXsiS的想法相似,但在承诺/差异对象方面有点结构化。

您可能需要检查这种方法


基于Kris Kowal的Q库。基本上与SynXsiS的想法相似,但在承诺/不同对象方面更具结构化。

google“multithread javascript”您可以在那里找到库和答案(今天我自己也搜索了相同的内容…),您有什么想法?老实说,我只是好奇。谷歌“多线程javascript”你可以在那里找到库和答案(今天我自己也搜索了相同的东西…)你有什么想法?老实说,我只是好奇。Web工作人员无法访问DOM,因此他们不会帮助进行“长时间运行的DOM逐节点漫游”。Web工作人员无法访问DOM,因此他们不会帮助进行“长时间运行的DOM逐节点漫游”。while(parent&&!parent.next())是否存在
问题
因为父对象是jQuery对象,所以它总是非空的。另外,它是否需要停止向上到达传入节点上方的父节点?@jfriend00您是对的。您可能希望检查父级的长度。关于检查父节点是否为起始节点,也请更正。该代码更像是psuedo代码,用于启动OP。while(parent&&!parent.next())是否存在问题,因为parent是jQuery对象,所以它总是非空的。另外,它是否需要停止向上到达传入节点上方的父节点?@jfriend00您是对的。您可能希望检查父级的长度。关于检查父节点是否为起始节点,也请更正。这段代码更像是psuedo代码,用于启动操作。