用jQuery实现异步DOM树遍历

问题描述 投票:1回答:4

我想对DOM进行长时间的运行,一个节点一个节点的走动,在每个节点上调用一个函数,但又不至于让浏览器无法响应。所以我想异步是最好的办法。

我觉得jQuery Deferred对象可以提供一个解决方案,但我还没能想出一个。

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

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

javascript jquery dom asynchronous tree-traversal
4个回答
1
投票

你可以用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();
    }
});

0
投票

如果你能使用HTML5,一些浏览器就会支持web worker。https:/developer.mozilla.orgEnUsing_web_workers。这可能是一个选择。 你也许可以把DOM作为文档传递给方法,然后从那里开始。


0
投票

你可以看看 https:/github.comwilsonpagefastdom。 就是这样,在dom中进行异步操作。


0
投票

你可能会想检查这个方法

https:/gist.github.comstelf4b6935071447724c7066。

基于Kris Kowal的Q库。基本上类似于SynXsiS的想法,但在PromisesDeffered对象方面结构更多一些。

© www.soinside.com 2019 - 2024. All rights reserved.