【问题标题】:Bluebird cancellation with await蓝鸟取消等待
【发布时间】:2019-10-19 21:51:32
【问题描述】:

此代码工作正常:

let promise;
try {
    promise = parent();
    //but I want: await parent();
    await continueStack();
} catch (e) {
    console.log('Caught error in endpoint');
}

eventBus.on('stop::all', () => {
    console.warn('Caught stop::all event');
    promise.cancel();
});

它正在取消对程序其他部分发出的事件的承诺。我的问题是我不能拥有await parent(),因为那时还没有执行监听事件。如果我改成这样:

let promise;
eventBus.on('stop::all', () => {
    console.warn('Caught stop::all event');
    promise.cancel();
});

try {
    promise = await parent();
    await continueStack();
} catch (e) {
    console.log('Caught error in endpoint');
}

那我有错误

TypeError: 无法读取未定义的属性“取消”

它崩溃了,continueStack() 永远不会被执行。我想如何调和这些?


我已经用上面的场景创建了整个示例:

https://gist.github.com/BorysTyminski/147dc2e0c44c8d64386253d563ff6db4

为了运行它,你需要获取这两个文件,安装 package.json 依赖并运行 cURL / Postman request GET to localhost:5000/test

【问题讨论】:

  • 有什么意义?为什么要在那里使用await?另外,promise = await parent(); 将 promise 的解析值存储在 let promise 中,而不是 promise 本身。因此promise.cancel 不存在,因为您没有承诺,只有已解决的值。
  • 因为我想在父函数之后执行 continueStack 并且我正在从父函数返回新的 Promise。
  • 谁/什么调度了stop::all 事件? parent() 是否有机会发送该事件?基本上打算取消它要返回的Promise?或者这是不可能发生的情况?
  • 事件是从其他线程上运行的后台进程发出的。基本上,我正在为带有硒的电子应用程序创建用于动态网络应用程序游戏的机器人。可以说parent 是在板上循环的函数。当后台进程检测到该怪物出现在板上时,我想取消parent。我将在稍后创建示例并编辑帖子。

标签: javascript promise bluebird cancellation


【解决方案1】:

您可以通过将promise var 设置为parent 来做到这一点,然后等待它:

const EventEmitter = require('events');
const Promise = require('bluebird');

Promise.config({
  cancellation: true,
})
const parent = new Promise(resolve => {
  setTimeout( () => {
    resolve();
  }, 100);
});

const continueStack = new Promise(resolve => {
  setTimeout( () => {
    resolve();
  }, 100);
});

let promise;

const emitter = new EventEmitter();

emitter.on('stop', function() {
  if(promise && promise.cancel){
    promise.cancel();
    console.log('promise cancelled');
  } else {
    console.log('somehow promise was not properly set at this point');
  }
});

setTimeout(_ => {
  emitter.emit('stop');
}, 80);

async function operation() {
  try {
  promise = parent;
  await promise;
  console.log('after promise. This log should never appear.');
  await continueStack;
    console.log('after wait 2. This log should never appear.');
  } catch(e) {
    console.log('Even if the promise is cancelled, this is not called.');
  }
}

operation();

(使用节点运行 sn-p 只会记录“已取消承诺”):在异步函数内部执行 await promise 之后什么都没有。

一些注意事项:

  • 需要Promise.config 将cancellable 设置为true。
  • await 不像睡眠。它不会阻塞 javascript 线程、事件侦听器或任何事件发射器。它只是确保await 之后的代码将等待等待的承诺。但这仅在异步函数的上下文中。

  • 取消 Promise 不会触发 catch 处理程序。这让我很困惑,但我想这就是它的工作原理。

【讨论】:

  • eventBus.on('stop::all'...) 部分必须在await promise 之前,否则毫无意义。
  • 它没有机会监听事件。 Await 的工作方式类似于其他编程语言中的 sleep() 函数。因此,您的示例监听事件是在 parent 和 continueStack 解析之后执行的,因此您的代码将无法工作
  • @Thomas 你说得对,我编辑了我的答案,我认为它不起作用
  • 但这不是我想要的行为。我只想取消 parent 并且我希望 continueStack 被执行。老实说,我真的不明白为什么从 try 块中只执行父级,而这个控制台和 continueStack 没有。
  • 它们没有被执行,因为它们是第一个 Promise 的处理程序。通过取消它,它的处理程序被取消。但是,如果您不需要 parent() 结果继续...为什么在调用 continueStack() 之前需要解决它?他们几乎是独立的,不是吗?为什么需要await parent()
猜你喜欢
  • 2015-02-13
  • 2015-06-26
  • 2018-10-02
  • 1970-01-01
  • 2018-10-23
  • 2014-07-31
  • 2019-09-29
  • 2020-04-23
  • 1970-01-01
相关资源
最近更新 更多