当我想打开一个窗口并检查打开的窗口的DOM中何时存在特定元素时,我使用了以下代码多年。它工作正常,从来没有问题。 PS:假设jQuery已经导入到该项目中。
openedWindow = window.open("http://localhost/teste1.php");
myClock = window.setInterval(
function() {
if ($(openedWindow.window.document).find("#myElement").length == 1) {
window.clearInterval(openedWindow);
//DO MY STUFF HERE.
}
},
100
);
因此,昨天我的一个朋友来找我,看到了这段代码,并说:“你应该带着诺言做到这一点”。他说他不知道诺言如何深入发挥作用,但是他说我的代码将变得更小并且更易于阅读。
好的。我也不知道诺言。因此,我研究了一个多小时,并想出了下面的代码,该代码可以“正常运行”。除了更大以外,我根本看不懂它。
new Promise(function(resolve,reject) {
openedWindow = window.open("http://localhost/teste1.php");
window.setInterval(
function() {
window.clearInterval(openedWindow);
if ($(openedWindow.window.document).find("#myElement").length == 1) {
resolve(true);
}
},
100
);
}).then(
function(result) {
if (result) {
//DO MY STUFF HERE.
}
}
);
所以我的朋友错了吗?还是我做错了做错了事的人?有没有更好的方法来实现我这个学科的新手没有看到的承诺?
答案 0 :(得分:3)
我将保留我的答案,因为我认为它对于理解Promises很有用。问题与等待DOM中的内容有关,但是我认为OP的主要关注点在于理解为什么人们会在回调中使用Promise。
但是,如此说来,对于与DOM更改相关的特定问题,Nino's answer是最好的。
除了更大,我根本看不懂。
嗯,我的想法是:
waitForElement
的函数,该函数接受element
并返回一个Promise,该Promise在找到该元素时进行解析。 element
的承诺。这很重要,因为您可以将回调附加到已解决的Promises上并继续运行(例如,如果您使用的是等待数据库连接的Promise,则这很重要)。所以您的功能将类似于:
function waitForElement(element){
return new Promise(function(resolve) {
// maybe uri could be a param too
openedWindow = window.open("http://localhost/teste1.php");
window.setInterval(
function() {
window.clearInterval(openedWindow);
if ($(openedWindow.window.document).find(element).length == 1) {
resolve(true);
}
},
100
);
});
}
在方法开始时注意return
。所以现在您的代码的任何部分都可以调用:
waitForElement('#foo').then( // do my stuff //);
正如您所说,这仍然几乎相同。但是,关于promise的好处是它们允许附加回调,并且它们缓存异步操作,因此现在您可以:
const fooIsPresent = waitForElement('#foo');
// later in your code
fooIsPresent( // some stuff //);
// and even later, maybe minutes later:
fooIsPresent(// still more stuff //);
现在,如果该元素仍然不存在,则当该时刻到来时,将调用填充回调。
但是,如果已经找到元素,然后您调用fooIsPresent
,则回调将立即执行(在下一个刻度中)。
如果您希望某些东西总是先于其他东西发生,则可以将它们链接起来:
fooIsPresent.then(// first stuff //)
.then(// second stuff //);
是的,代码更大,也许不太清楚,但是现在更有用了,您可以通过一些便捷的方式来使用它。
答案 1 :(得分:2)
我同意您的评估;您的Promises版本较长,并且没有任何清晰度。有人认为Promises会使所有代码变得更好,这是不正确的。无论您是否使用Promises,您都可以编写或编写不佳的代码。我个人发现,Promises常常会弄不清楚。
在第一个示例中,我认为您打算将myClock
传递给clearInterval()
。无论如何,当我认为它可能会很快被取消时,我更喜欢使用setTimeout
。
我喜欢拥有一个独立的结构。
(function checker(openedWindow) {
if (openedWindow.window.document.querySelector("#myElement")) {
doMyStuff(openedWindow);
} else {
setTimeout(checker, 100, openedWindow);
}
})(window.open("http://localhost/teste1.php"));
function doMyStuff(openedWindow) {
// DO MY STUFF
}
答案 2 :(得分:2)
你们俩都错了,但比他错了很多,因为按照承诺编写这段代码可以使您更好地区分代码:
/* without promises */
// code for waiting for an element to appear
// code for after
// code for waiting for an element to appear
/* with promises */
// code for waiting for an element to appear
// code for after
但是,你们俩都错了,因为等待元素出现的现代方式是使用mutation observers:
const observer = new MutationObserver(mutationRecordList => {
for (mutationRecord of mutationRecordList) {
if (mutationRecord.target.getAttribute('id')=='#my-element') {
console.log('The element just appeared');
}
}
});
observer.observe(document.body, {childList: true, subtree: true});
并根据您的代码将整个内容包装成一个承诺。