【问题标题】:resolving a promise with EventListener使用 EventListener 解决承诺
【发布时间】:2021-06-26 04:16:23
【问题描述】:

我正在制作一个弹出式 div,我希望在动画上附加一个承诺,以便在弹出式结束后我可以做一些事情。

我的方法不起作用,因为我找不到将承诺传递给事件处理程序上的函数的方法。似乎你不能在这里使用绑定。我已经尝试过,虽然我可以解决承诺,但我无法删除事件处理程序

这里有什么不同的解决方案?

function EventListenerForPopUp() {
    this.removeEventListener("animationend", EventListenerForPopUp );
    this.Show.resolve();
}   

function ShowHideDiv() {        
    this.Show = function () { 
        return new Promise(function(resolve, reject) {
            this.Div.addEventListener("animationend", EventListenerForPopUp, false);
        }.bind(this));
    }
}

【问题讨论】:

  • addEventListener 用于在对象或 DOM 元素上设置事件。它需要一个回调,这是“旧”的做事方式。难道没有一种简单的方法可以将 addEventListener 包装在 Promise 中,以便可以使用 'then' 和 'catch' 吗?我很想在我的程序中使用这种一致性。这个问题似乎还没有一个可以接受的答案,即使在 2 年后也是如此。
  • 当然,明显的区别是同一个事件可以一次又一次地发生,而单个异步操作只发生一次。 Promise 有一个 Pending 状态,该状态仅更改一次为 Fulfilled 或 Rejected 状态。这与重复发生的事件不太匹配。对重复出现的 setInterval 也不是很好匹配,但对出现一次的 setTimeout 很好匹配。

标签: javascript


【解决方案1】:

您不需要将promise传递给事件处理程序,您需要传递resolve回调:

function EventListenerForPopUp(resolve) {
            this.removeEventListener("animationend", EventListenerForPopUp );
            resolve();
}   

// [...]

        return new Promise(function(resolve, reject) {
            this.Div.addEventListener("animationend", function() {
                EventListenerForPopUp.call(this, resolve);
            }, false);

这对我来说有点难看,也许你可以看看这样的东西:

var div = this.Div;
return new Promise(function (resolve) {
    div.addEventListener("animationend", function animationendListener() {
        div.removeEventListener("animationend", animationendListener);
        //call any handler you want here, if needed
        resolve();
    });
});

【讨论】:

  • 感谢您的信息。第一个选项没有删除事件监听器。
  • 我使用第二种方法。已经看到一些关于不使用局部变量来携带这个对象的评论。但在这种情况下,还没有找到不这样做的方法
  • 第一个选项没有删除事件监听器我想这就是为什么第一个解决方案对作者来说有点难看。
【解决方案2】:

或者,我们可以创建一个可重用的实用程序函数,作为从任何 DOM 事件创建 Promise 的一种方式:

const createPromiseFromDomEvent = (eventTarget, eventName, run?) =>
    new Promise((resolve, reject) => {
        const handleEvent = () => {
            eventTarget.removeEventListener(eventName, handleEvent);

            resolve();
        };

        eventTarget.addEventListener(eventName, handleEvent);

        try {
            if (run) run();
        catch (err) {
            reject(err);
        }
    });

使用示例(使用 MSE 源缓冲区):

await createPromiseFromDomEvent(
    sourceBuffer,
    'update',
    () => sourceBuffer.remove(3, 10)
);

根据情况,run 参数可能需要提供自定义代码来触发异步操作(如上),或者如果我们知道操作已经开始,则省略。

【讨论】:

    【解决方案3】:

    另一种选择是将外部控制的 Promise 抽象为可重用函数 -

    function thread () {
      let resolve, reject
      const promise = new Promise((res, rej) => {
        resolve = res
        reject = rej
      })
      return [promise, resolve, reject]
    }
    
    function customPrompt(form) {
      const [prompt, resolve] = thread()
      form.yes.addEventListener("click", _ => resolve(true), {once: true})
      form.no.addEventListener("click", _ => resolve(false), {once: true})
      return prompt
    }
    
    customPrompt(document.forms.myform)
      .then(response => console.log("response:", response))
    <form id="myform">
      <input type="button" name="yes" value="yes" />
      <input type="button" name="no" value="no" />
    </form>

    如果需要,您可以使用 async 和 await -

    async function main () {
      const response = await customPrompt(document.forms.myform)
      console.log("response:", response)
    }
    

    您可以通过修改 customPrompt 轻松添加超时 -

    function customPrompt(form) {
      const [prompt, resolve, reject] = thread()
      form.yes.addEventListener("click", _ => resolve(true), {once: true})
      form.no.addEventListener("click", _ => resolve(false), {once: true})
      
      // timeout after 30 seconds
      setTimeout(reject, 30000, Error("no response"))
      return prompt
    }
    

    有关thread 的其他创造性用途,请参阅this Q&A。

    【讨论】:

      猜你喜欢
      • 2015-06-24
      • 1970-01-01
      • 1970-01-01
      • 2019-09-29
      • 1970-01-01
      • 2020-03-16
      • 2022-12-05
      • 2018-04-02
      • 2022-01-22
      相关资源
      最近更新 更多