Làm cách nào để tôi có thể `chờ đợi 'trên Rx Observable?


106

Tôi muốn có thể chờ đợi một điều có thể quan sát được, ví dụ:

const source = Rx.Observable.create(/* ... */)
//...
await source;

Một nỗ lực ngây thơ dẫn đến việc đang chờ giải quyết ngay lập tức và không chặn việc thực thi

Chỉnh sửa: Mã giả cho trường hợp sử dụng dự kiến ​​đầy đủ của tôi là:

if (condition) {
  await observable;
}
// a bunch of other code

Tôi hiểu rằng tôi có thể di chuyển mã khác vào một hàm riêng biệt khác và chuyển nó vào lệnh gọi lại đăng ký, nhưng tôi hy vọng có thể tránh được điều đó.


Bạn có thể không di chuyển mã còn lại (mà bạn muốn đợi nguồn) vào một .subscribe()cuộc gọi phương thức?
StriplingWarrior

Câu trả lời:


132

Bạn phải vượt qua một lời hứa await. Chuyển sự kiện tiếp theo của người có thể quan sát thành một lời hứa và chờ đợi điều đó.

if (condition) {
  await observable.first().toPromise();
}

Chỉnh sửa ghi chú: Câu trả lời này ban đầu được sử dụng .take (1) nhưng đã được thay đổi thành .first () để tránh vấn đề Lời hứa không bao giờ giải quyết nếu luồng kết thúc trước khi một giá trị đi qua.


3
Thay vì lấy (1), bạn có thể sử dụng await observable.first().toPromise();?
apricity

14
@apricity Nếu không có giá trị nào khi hoàn thành, first()sẽ dẫn đến việc bị từ chối và take(1)dẫn đến lời hứa đang chờ xử lý.
Estus Flask

6
@apricity @AgentME Trên thực tế, bạn KHÔNG nên sử dụng cả take(1)hoặc first()trong những trường hợp như thế này. Vì bạn đang mong đợi chính xác MỘT sự kiện xảy ra, bạn nên sử dụng single()nó sẽ ném một ngoại lệ nếu có nhiều hơn 1, trong khi không ném một ngoại lệ khi không có. Nếu có nhiều hơn một thì có thể có điều gì đó sai trong mô hình mã / dữ liệu của bạn, v.v. Nếu bạn không sử dụng đơn lẻ, bạn sẽ tự ý chọn mục đầu tiên trả về mà không cảnh báo rằng có nhiều mục khác. Bạn sẽ phải quan tâm đến vị từ của mình trên nguồn dữ liệu ngược dòng để luôn duy trì cùng một thứ tự.
ntziolis

3
Đừng quên nhập:import 'rxjs/add/operator/first';
Stephanie

7
Bây giờ toPromise () không được dùng nữa, chúng ta nên làm như thế nào?
10

26

Nó có thể phải là

await observable.first().toPromise();

Như nó đã được lưu ý trong các nhận xét trước đây, có sự khác biệt đáng kể giữa take(1)và các first()toán tử khi có trống hoàn thành có thể quan sát được.

Observable.empty().first().toPromise()sẽ dẫn đến từ chối với EmptyErrorđiều đó có thể được xử lý tương ứng, bởi vì thực sự không có giá trị.

Observable.empty().take(1).toPromise()sẽ dẫn đến độ phân giải với undefinedgiá trị.


Trên thực tế take(1)sẽ không mang lại một lời hứa đang chờ xử lý. Nó sẽ mang lại một lời hứa được giải quyết với undefined.
Johan t Hart

Cảm ơn bạn đã chú ý, điều đó chính xác. Tôi không chắc tại sao bài đăng khác nhau, có thể hành vi đã thay đổi tại một số điểm.
Estus Flask

8

Bạn sẽ cần awaitmột lời hứa, vì vậy bạn sẽ muốn sử dụng toPromise(). Xem điều này để biết thêm chi tiết về toPromise().


4

Nếu bạn toPromisekhông dùng nữa, bạn có thể sử dụng .pipe(take(1)).toPromisenhưng như bạn có thể thấy ở đây, nó không bị dùng nữa.

Vì vậy, vui lòng sử dụng toPromise(RxJs 6) như đã nói:

//return basic observable
const sample = val => Rx.Observable.of(val).delay(5000);
//convert basic observable to promise
const example = sample('First Example')
  .toPromise()
  //output: 'First Example'
  .then(result => {
    console.log('From Promise:', result);
  });

ví dụ async / await:

//return basic observable
const sample = val => Rx.Observable.of(val).delay(5000);
//convert basic observable to promise
const example = await sample('First Example').toPromise()
// output: 'First Example'
console.log('From Promise:', result);

Đọc thêm tại đây .

Và vui lòng xóa xác nhận quyền sở hữu sai này nói rằng toPromisekhông được dùng nữa.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.