Node.js 程序在 `finally {}` 之后不运行 `try {}` block 并以代码 0 退出

标签 node.js rxjs

今天我在 Node.js 中使用 RxJS 编写一些代码,并得到了非常好的结果:程序运行 try{}阻止但未运行 finally{}完全阻止,在 try{} 内使用代码 0 退出 block 。

在缩短我的代码后,为了重现此问题,步骤如下:

  1. 首先创建一个BehaviorSubject命名subject
  2. 调用 subject.asObservable().share()并获得一个名为 obs 的 Observable
  3. 调用 obs.subscribe()
  4. 调用 await obs.first().toPromise()

然后,最后,程序执行了一个非常有线的行为:退出 try {}阻止而不运行以下代码 finally {} block 。

重现它的 TypeScript 代码如下:运行它,然后你将得到一行输出:1. BEFORE TRY ,这不是预期的!

import {
  BehaviorSubject,
}                     from 'rxjs/Rx'

async function main() {
  const subject = new BehaviorSubject<number>(-1)
  const obs = subject.asObservable().share()

  /**
   * if comment the following line, this program will output right as the following three lines:
   *
   * 1. BEFORE TRY
   * 2. AFTER TRY
   * 3. FINALLY
   *
   * otherwise, the output will only be:
   *
   * 1. BEFORE TRY
   *
   * very wired!
   *
   */
  obs.subscribe()

  try {
    console.log('1. BEFORE TRY')

    await obs.first().toPromise()

    console.log('2. AFTER TRY')
  } finally {
    console.log('3. FINALLY')
  }

}

main()

我的问题是:Node.js 如何在 try{} 内退出阻止而不运行 finally{} block ,退出代码为 0?

有人有想法吗?

环境:

$ uname -a
Darwin zixia-pro.lan 16.7.0 Darwin Kernel Version 16.7.0: Tue Jan 30 11:27:06 PST 2018; root:xnu-3789.73.11~1/RELEASE_X86_64 x86_64
$ node --version
v9.8.0
$ grep rxjs ../package.json 
    "rxjs": "^5.5.6"

更新

根据@martin的回答,我意识到这是Node.js的行为。

我编写了一个可重现的程序来演示如何在 try{} 中退出 Node.js阻止并以代码 0 退出,而不运行 finally{} block ,非常简单:WAITING一个永不解析的 Promise。

async function main() {
  try {
    await new Promise(r => console.log('IN TRY BLOCK'))
  } finally {
    console.log('IN FINALLY BLOCK')
  }
}

main()

上面的程序只会输出IN TRY BLOCK并以代码 0 退出,无输出 IN FINALLY BLOCK完全没有。

对于也觉得这很奇怪的读者,我还在 https://github.com/nodejs/node/issues/19929 上打开了一个关于 Node 的问题。

最佳答案

由于您使用的运算符,这实际上是正确的行为。

您正在创建一个 BehaviorSubject(-1),它向每个新订阅者发出 -1。然后你就可以使用 share()始终只保留对其源 Observable 的一个订阅

这是最重要的事情。当您使用 obs.subscribe() 时,它会使 share 订阅其源(实际上是 subject),并发出 -1 立即,但该值不会在任何地方打印,因为您使用了 .subscribe() 的空订阅者。

然后,您使用 await obs.first().toPromise() 创建另一个订阅者,但仍然有第一个订阅者订阅,因此 share() 维护此单一订阅subject 因此源 BehaviorSubject 永远不会再次发出,这意味着 .toPromise() 中的 Promise 永远不会被解析,因此 await永远等待。

但是,如果您使用而不是 obs.subscribe() 例如:

obs.take(1).subscribe(console.log);

查看控制台输出:https://stackblitz.com/edit/rxjs5-pev27v?file=index.ts

...您将看到预期的输出,因为 take(1) 在收到 -1 后立即取消订阅,然后收到第二个订阅者 toPromise()share() 再次订阅 subject 并发出 -1 并成功解析 Promise。

关于Node.js 程序在 `finally {}` 之后不运行 `try {}` block 并以代码 0 退出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49728838/

相关文章:

angular - 对 Observable zip 订阅执行操作

rxjs - ReactiveX/Rx.NET 中 RxJS switchMap 的等效项

mysql - 如何通过NodeJS插入MySQL中的Orders表和Order Items表

Angular 7 按日期对 Observable.subscribe() 排序?

Node.js -Couchbase - 警告 : We are having troubles communicating to the indexer process. 该信息可能已过时

javascript - 如何流式传输 blob

angular - 如何正确使用 RxJS 为返回到 Observable 的数组的每个对象添加一个新字段?

javascript - 如何在 RxJS 中通过点击流从一个流遍历数组?

javascript - 在 Nest.js 中使用 HTTP 在模块之间进行通信

javascript - 使用最小值/最大值随机分块字节