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

时间:2018-04-09 08:42:47

标签: node.js rxjs

今天我在Node.js中用RxJS编写了一些代码并得到了非常有线的结果:程序运行try{}块,但根本没有运行finally{}块,退出代码0在try{}区块内。

使我的代码简短后,为了重现这个问题,步骤是:

  1. 首先创建名为BehaviorSubject
  2. subject
  3. 调用subject.asObservable().share()并获取名为obs
  4. 的Observable
  5. 致电obs.subscribe()
  6. 致电await obs.first().toPromise()
  7. 然后,最后,程序执行非常有线的行为:退出try {}块而不运行以下finally {}块内的代码。

    重现它的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{}块,退出代码为0?

    有没有人有想法?

    ENV:

    $ 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{}块,这非常简单:等待永不解决的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

    为节点打开了一个问题

2 个答案:

答案 0 :(得分:1)

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

您正在为每个新订阅者创建BehaviorSubject(-1) -1。然后你有share() 始终只保留一个订阅源Observable

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

然后,您使用await obs.first().toPromise()创建了另一个订阅者,但仍然是订阅的第一个订阅者,因此share()维护此单一订阅subject所以来源BehaviorSubject永远不会再发出这意味着.toPromise()中的承诺永远不会被解决,所以await会一直等待。

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

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

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

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

答案 1 :(得分:0)

你想要达到什么目的?为什么要创建和Observable然后立即将其转换为Promise?

如果您需要处理&#34;事件流&#34;,您可以创建一个Observable。

这是一个使用Observables的例子,从你的

以某种方式派生
import {BehaviorSubject} from 'rxjs/Rx'

const subject = new BehaviorSubject<number>(-1)
const obs = subject.asObservable().share();

console.log('1. BEFORE SUBCRIPTION');
obs
.subscribe(
    aNumber => console.log('2. PROCESSING SUBCRIPTION', aNumber),
    err => console.error(err),
    () => console.log('3. COMPLETED OBSERVABLE')
)

subject.next(0);
subject.next(1);
subject.next(2);
subject.complete();