有没有更好的办法来兑现承诺?

时间:2019-04-06 12:44:31

标签: javascript

当我想打开一个窗口并检查打开的窗口的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.

        }

    }

);

所以我的朋友错了吗?还是我做错了做错了事的人?有没有更好的方法来实现我这个学科的新手没有看到的承诺?

3 个答案:

答案 0 :(得分:3)

免责声明:

我将保留我的答案,因为我认为它对于理解Promises很有用。问题与等待DOM中的内容有关,但是我认为OP的主要关注点在于理解为什么人们会在回调中使用Promise。

但是,如此说来,对于与DOM更改相关的特定问题,Nino's answer是最好的。

原始答案

  

除了更大,我根本看不懂。

嗯,我的想法是:

  1. 您将公开一个类似waitForElement的函数,该函数接受element并返回一个Promise,该Promise在找到该元素时进行解析。
  2. 现在您的代码的任何部分都可以使用此功能来找到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});

并根据您的代码将整个内容包装成一个承诺。