在rxjs中的异步清理逻辑?

huangapple go评论48阅读模式
英文:

Async teardown logic in rxjs?

问题

Here is the translated code part you requested:

我有一个书籍ID的可观察对象
```typescript
const bookId$ = new Subject<string>();

在后端有一个LibraryService,允许前端通过调用borrowAsync(id: string) -> Promise<Book>来借书,然后通过调用returnAsync(id:string) -> Promise<void>来归还书籍。规则是:1) 一次只能借一本书,2) 每本借出去的书都必须归还。

现在我想将book_id$转换为已借阅书籍的可观察对象:

const book$ = bookId$.pipe( //...

我该如何实现这个?我考虑使用switchMap

const book$ = bookId$.pipe(
  switchMap(bookId => {
    return new Observable<Book> (observable => {
      let currentBook: Book | undefined = undefined;
      LibraryService.borrowAsync(bookId).then(
        book => {
          currentBook = book;
          observable.next(book);
          observable.complete();
        },
        // 在生产代码中也处理错误
      );

      // 清理逻辑
      return () => {
        if (currentBook) {
          LibraryService.returnAsync(currentBook.id);  // !!! 未等待
        }
      };
    });
  })
);

如果生成了新的bookId,则会执行以前借出的书籍的清理逻辑(如果存在)。但关键问题在于,由于归还过程是异步的,我们必须等待它完成,才能借下一本书,所以这段代码无法正常工作。


<details>
<summary>英文:</summary>

Say I have an observable of book ids:
```typescript
const bookId$ = new Subject&lt;string&gt;();

In the backend there is a LibraryService which allows the frontend to borrow a book by calling borrowAsync(id: string) -&gt; Promise&lt;Book&gt; and return it by calling returnAsync(id:string) -&gt; Promise&lt;void&gt;. The rule is, 1) only one book can be borrowed at a time, and 2) every borrowed book must be returned.

Now I'd like to transform the book_id$ to an observable of borrowed book:

const book$ = bookId$.pipe( //...

How do I achieve this? I'm thinking switchMap:

const book$ = bookId$.pipe(
  switchMap(bookId =&gt; {
    return new Observable&lt;Book&gt; (observable =&gt; {
      let currentBook: Book | undefined = undefined;
      LibraryService.borrowAsync(bookId).then(
        book =&gt; {
          currentBook = book;
          observable.next(book);
          observable.complete();
        },
        // also handles error in the production code
      );

      // teardown logic
      return () =&gt; {
        if (currentBook) {
          LibraryService.returnAsync(currentBook.id);  // !!! NOT AWAITED
        }
      };
    });
  })
);

It's good if a new bookId has been produced, the teardown logic will be executed for the previously borrowed book (if existed); but the catch here is, since the returning process is async, we'll have to await it to complete, in order to borrow the next book, so this piece of code won't work.

答案1

得分: 1

this.book$ = this.bookId$.pipe(
      switchMap((id) =&gt; {
        return concat(
          from(this.library.returnCurrentBorrowedBookAsync()).pipe(
            ignoreElements() // because we don&#39;t want the result of that operation
          ),
          this.library.borrowAsync(id)
        );
      })
    );
  }

魔法在于 concat 操作符:我们确保在从图书馆借取新书之前释放当前的书籍。
注意 from 将 Promise 转换为 Observable。

我假设 returnAsync 操作总是成功的。
工作示例: https://stackblitz.com/edit/stackblitz-starters-aggs1n?file=src%2Fmain.ts

英文:

You can so something like:

this.book$ = this.bookId$.pipe(
      switchMap((id) =&gt; {
        return concat(
          from(this.library.returnCurrentBorrowedBookAsync()).pipe(
            ignoreElements() // because we don&#39;t want the result of that operation
          ),
          this.library.borrowAsync(id)
        );
      })
    );
  }

The magic lays in the concat operator: we make sure to release the current book before taking a new one from the libary.
Note from converts Promise to Observable.

I assume that the returnAsync is always successful.
Working example: https://stackblitz.com/edit/stackblitz-starters-aggs1n?file=src%2Fmain.ts

答案2

得分: 0

这是一个在这里讨论过的功能请求。在不久的将来,rxjs(或者任何ReactiveX实现,如果有的话)不太可能实现它。

英文:

This is a feature request discussed here. It's not likely to be implemented in rxjs (or any ReactiveX implementation, if that matters) in the near future.

huangapple
  • 本文由 发表于 2023年5月29日 18:37:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76356612.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定