如何使用 JavaScript 等待元素存在?

问题描述 投票:0回答:3

我正在使用

proxy object
,在其中检测对象值更改,然后通过 AJAX 加载新内容,我使用
setInterval
函数等待 AJAX 请求中出现的元素存在,然后执行一个片段的代码。我这样做是因为我的情况需要这样做。我做了一个简短的例子:

var handler = {
    makeThings: 0,
    otherStuff: 0
};
var globalHandler = new Proxy(handler, {
    set: function(obj, prop, value) {
        obj[prop] = value
        if (prop == "makeThings") {
            var clearTimeSearchProxy = setInterval(function() {
                if ($("p").length) {
                    console.log("The element finally exist and we execute code");
                    clearTimeout(clearTimeSearchProxy);
                }
            }, 100);
        }
        return true;
    }
});

$(document).ready(function() {
    $("button").on("click", function() {
        globalHandler.makeThings = 1;
        //This element comes with ajax but I use a setTimeout for this example
        setTimeout(function() {
            $("#newContent").append("<p>Ajax element</p>");
        }, 2000);
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
  <button>New content</button>
  <div id="newContent"></div>
</body>

现在我想知道如何以更干净、高效、优雅的方式改进代码。当通过 AJAX 传入的元素存在于

promises
中时,我正在考虑使用
setInterval
而不是
DOM
来执行代码。

我怎样才能让它发挥作用?在这种情况下我应该使用其他 JavaScript 功能而不是

promises
吗?我坚持实现我所需要的承诺,这是我迄今为止所尝试的。

var handler = {
    makeThings: 0,
    otherStuff: 0
};
var globalHandler = new Proxy(handler, {
    set: function(obj, prop, value) {
        obj[prop] = value
        if (prop == "makeThings") {
            var myFirstPromise = new Promise((resolve, reject) => {
                if ($("p").length) {
                    resolve("Exist");
                } else {
                    reject("It doesnt exist.");
                }
            });

            myFirstPromise.then((data) => {
                console.log("Done " + data);
            }).catch((reason) => {
                console.log("Handle rejected promise: " + reason);
            });
        }
        return true;
    }
});

$(document).ready(function() {
    $("button").on("click", function() {
        globalHandler.makeThings = 1;
        //This element comes with ajax but I use a setTimeout for this example
        setTimeout(function() {
            $("#newContent").append("<p>Ajax element</p>");
        }, 2000);
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
  <button>New content</button>
  <div id="newContent"></div>
</body>

javascript jquery ecmascript-6 promise es6-promise
3个回答
5
投票

不要等待。而是订阅目标元素更改的通知。

用于监听 DOM 树中变化的 API 是 MutationObserver

MutationObserver 接口提供了监视 DOM 树发生更改的能力。它被设计为替代旧的 Mutation Events 功能,该功能是 DOM3 Events 规范的一部分。

使用它来观察元素的变化,如下所示:

// You selected `$("p")` in your snippet, suggesting you're watching for the inclusion of 'any' `p` element.
// Therefore we'll watch the `body` element in this example
const targetNode = document.body;

// Options for the observer (which mutations to observe)
const config = {
    attributes: false,
    characterData: false,
    childList: true,
    subtree: true
};

// Callback function to execute when mutations are observed
const callback = function(mutationsList, observer) {
    for(let mutation of mutationsList) {

        if ( mutation.type === "childList" ) {
            continue;
        }

        const addedNodes = Array.from( mutation.addedNodes) ;

        if ( addedNodes && addedNodes.some( node => node.nodeName === "P" ) ) {
            observer.disconnect();

            console.log("The element finally exist and we execute code");
        }
    }
};

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

5
投票

我终于用 MutationObserver

interface
以一种简单的方式做到了,而不是用
promises

var handler = {
    makeThings: 0,
    otherStuff: 0
};
var globalHandler = new Proxy(handler, {
    set: function(obj, prop, value) {
        obj[prop] = value
        if (prop == "makeThings") {
            var observer = new MutationObserver(function(mutations) {
                if ($("p").length) {
                    console.log("Exist, lets do something");
                    observer.disconnect();
                }
            });
            // start observing
            observer.observe(document.body, {
                childList: true,
                subtree: true
            });
        }
        return true;
    }
});

$(document).ready(function() {
    $("button").on("click", function() {
        $("p").remove();
        globalHandler.makeThings = 1;
        //This element comes with ajax but I use a setTimeout for this example
        setTimeout(function() {
            $("#newContent").append("<p>Ajax element</p>");
        }, 2000);
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
  <button>New content</button>
  <div id="newContent"></div>
</body>


1
投票

rxjs 可以高度简化您想要做的事情。一个非常基本的实现,仅使用主题和订阅:

const {
  Subject
} = rxjs;

const sub = new Subject();

sub.subscribe(e => {
  console.log(`received data ${e}`);
  // do your thing
});

// simulate something async
setTimeout(() => {
  sub.next('foo');
}, 1000);
<script src="https://unpkg.com/[email protected]/bundles/rxjs.umd.min.js"></script>

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