【问题标题】:JS - Return empty promise and resolve it laterJS - 返回空承诺并稍后解决
【发布时间】:2021-05-05 01:20:58
【问题描述】:

在 JS 中,我想:

  1. 定义一个定义承诺的函数。
  2. 这个函数然后有一个事件来解决这个承诺。
  3. 该函数返回未解决的承诺。
  4. 当 promise 被解析时,调用者将收到解析的值。

类似这样的:

function my_func() {
    // This creates an empty promise.
    const p = Promise;

    // When a user clicks a button in UI then we resolve the promise.
    // This would be in an event!
    // p.resolve('user clicked OK');

    // Returns empty promise.
    return p;
}

function main() {
    // Here when the promise is resolved then we get the value.
    my_func().then(function(v) {
        console.log(v);
    });
}

【问题讨论】:

  • 就这样吧? return new Promise(resolve => { okButton.onclick = (e) => resolve('user clicked ok'); })

标签: javascript function promise


【解决方案1】:

这似乎是一个奇怪的设计,但作为 Bergi cmets,没有什么能阻止你这样做 -

function my_func () {
  return new Promise(r =>
    document.forms.myapp.mybutton.onclick = r
  )
}

function main () {
  my_func().then(event => console.log(event.target))
}

main()
<form id="myapp">
  <button type="button" name="mybutton">Click me</button>
</form>

Promise 最多可以解决一次次,因此在第一次单击后自动删除事件侦听器可能是有意义的。我们可以将 my_func 重命名为 onclick 并给它一个参数以使其可重用 -

function onclick(elem) {
  return new Promise(r =>
    elem.addEventListener("click", r, {once: true})
  )
}

function main () {
  onclick(document.forms.myapp.mybutton)
    .then(event => console.log(event.target))
    
  onclick(document.forms.myapp.otherbutton)
    .then(event => console.log(event.target))
}

main()
<form id="myapp">
  <button type="button" name="mybutton">A</button>
  <button type="button" name="otherbutton">B</button>
</form>

现在onclick 可以以更有趣的方式使用。例如,我们可以制作一个需要 两次 次点击才能触发效果的按钮 -

function onclick(elem) {
  return new Promise(r =>
    elem.addEventListener("click", r, {once: true})
  )
}

function main () {
  onclick(document.forms.myapp.mybutton)
    .then(event => console.log(event.target))
    
  onclick(document.forms.myapp.otherbutton)
    .then(_ =>
      onclick(document.forms.myapp.otherbutton)
        .then(event => console.log(event.target))
    )
}

main()
<form id="myapp">
  <button type="button" name="mybutton">click once</button>
  <button type="button" name="otherbutton">click twice</button>
</form>

【讨论】:

  • 我看不出有什么奇怪的,OPs 列表中的所有四个点对于返回一个 Promise 的 每个 函数都是非常标准的用法。
  • 好的,但是我正在寻找一种方法来返回没有函数的承诺,因为我会将这个承诺传递到其他地方,然后我会在那里解决它。不过好像没办法。
  • @user5507535 如果其他地方负责解决承诺,那么其他地方应该构建它。您要解决的实际问题是什么?
  • +1 使用{once: true}
  • 如果遇到错误的方式,我深表歉意。我只是说通过addEventListener 使用 Promise 而不是事件监听器有点不合常规
【解决方案2】:

在这里找到答案:Creating a (ES6) promise without starting to resolve it

deferreds 可以随意传递,然后可以在其他地方解决或拒绝承诺。
还没有在代码中测试过,所以不知道这种方法是否有任何问题。

function my_func() {
  const deferreds = [];
  const p = new Promise(function (resolve, reject) {
    deferreds.push({ resolve: resolve, reject: reject });
  });
  const btn = document.querySelector('.btn');

  btn.addEventListener('click', event => {
    deferreds[0].resolve('User clicked button!');
  }, {once: true});

  return p;
}

function main() {
  my_func().then(function (v) {
    console.log(v);
  });
}

main();
<button class="btn">
    Hi! Click me
</button>

【讨论】:

  • 如果您可以在问题中显示您的真实代码,这将有所帮助。在您答案中的示例my_func 代码中,绝对没有理由使用延迟对象,您可以(应该!)只需将addEventListener 调用放在new Promise 执行程序中。仅当您拥有它们的集合时才需要使用延迟对象的方法,而其他一些代码会动态地决定要解决的哪些 - 这就是为什么deferreds 是链接答案中的一个数组。但在你的情况下,这似乎是不必要的。
  • 不幸的是,我的代码有点复杂,它是一个 ExtJS 窗口,里面有一个表单,我想在窗口显示时创建一个承诺并将其作为属性分配给表单。当用户单击表单上的按钮时,它将隐藏窗口并使用表单答案履行承诺。我不知道为什么 JS 不允许一个人创建一个空的承诺并做这种事情,对我来说似乎更简单直观的是能够这样做。
  • 主要是因为“空承诺”需要从外部解决 - 即每个有权访问承诺对象的人都可以解决它。这很容易出错,甚至是一个安全问题,promise 是严格的单向通信。即使在您的情况下,显示窗口的函数也应该创建承诺,安装事件侦听器,并将承诺存储在表单对象中 - no need for deferreds。还有deferred pattern is not exception-safe.
猜你喜欢
  • 2016-04-05
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 2016-08-19
  • 2019-10-01
  • 2021-05-25
  • 1970-01-01
  • 2016-07-05
相关资源
最近更新 更多