Helpex - Trao đổi & giúp đỡ Đăng nhập
61

Tôi hiện đang đánh giá những ưu nhược điểm của việc thay thế ứng dụng Angular. RxJS' Observablevới đồng bằng Promiseđể tôi có thể sử dụng asyncawaitvà nhận được một mã phong cách trực quan hơn.

Một trong những tình huống điển hình của chúng tôi: Tải một số dữ liệu bên trong ngOnInit. Sử dụng Observables, chúng tôi làm:

ngOnInit () {
  this.service.getData().subscribe(data => {
    this.data = this.modifyMyData(data);
  });
}

Khi tôi trả về Promisetừ getData()thay thế, và sử dụng asyncawait, nó sẽ trở thành:

async ngOnInit () {
  const data = await this.service.getData();
  this.data = this.modifyMyData(data);
}

Bây giờ, rõ ràng, Angular sẽ không "biết", điều đó ngOnInitđã trở thành async. Tôi cảm thấy rằng đây không phải là vấn đề: Ứng dụng của tôi vẫn hoạt động như trước đây. Nhưng khi tôi nhìn vào OnInitgiao diện, rõ ràng hàm không được khai báo theo cách có thể gợi ý rằng nó có thể được khai báo async:

ngOnInit(): void;

Vì vậy - điểm mấu chốt: Có hợp lý những gì tôi đang làm ở đây không? Hay tôi sẽ gặp phải bất kỳ vấn đề khó hiểu nào?

61 hữu ích 5 bình luận 44k xem chia sẻ
49

Nó không khác gì những gì bạn đã có trước đây. ngOnInitsẽ trả lại một Lời hứa và người gọi sẽ bỏ qua lời hứa đó. Điều này có nghĩa là người gọi sẽ không đợi mọi thứ trong phương thức của bạn kết thúc trước khi nó tiếp tục. Trong trường hợp cụ thể này, điều đó có nghĩa là chế độ xem sẽ hoàn tất được cấu hình và chế độ xem có thể được khởi chạy trước khi this.datađược thiết lập.

Đó là tình huống tương tự như bạn đã có trước đây. Người gọi sẽ không đợi đăng ký của bạn hoàn tất và có thể sẽ khởi chạy ứng dụng trước khi this.datađược phổ biến. Nếu chế độ xem của bạn đang dựa vào datathì bạn có thể có một số loại ngIfthiết lập để ngăn bạn truy cập nó.

Cá nhân tôi không thấy điều đó là khó xử hay là một việc làm xấu miễn là bạn nhận thức được những hệ lụy. Tuy nhiên, điều này ngIfcó thể rất tẻ nhạt (chúng sẽ cần thiết theo cả hai cách). Cá nhân tôi đã chuyển sang sử dụng trình giải quyết tuyến đường khi nó hợp lý để tôi có thể tránh tình huống này. Dữ liệu được tải trước khi tuyến đường kết thúc điều hướng và tôi có thể biết dữ liệu có sẵn trước khi chế độ xem được tải.

49 hữu ích 2 bình luận chia sẻ
25

Bây giờ, rõ ràng, Angular sẽ không "biết", rằng ngOnInit đã trở thành không đồng bộ. Tôi cảm thấy rằng đây không phải là vấn đề: Ứng dụng của tôi vẫn hoạt động như trước đây.

Về mặt ngữ nghĩa, nó sẽ biên dịch tốt và chạy như mong đợi, nhưng sự thuận tiện của việc viết async / waitđi kèm với chi phí xử lý lỗi, và tôi nghĩ nên tránh.

Hãy xem điều gì sẽ xảy ra.

Điều gì xảy ra khi một lời hứa bị từ chối:

public ngOnInit() {
    const p = new Promise((resolver, reject) => reject(-1));
}

Ở trên tạo ra dấu vết ngăn xếp sau:

core.js:6014 ERROR Error: Uncaught (in promise): -1
    at resolvePromise (zone-evergreen.js:797) [angular]
    at :4200/polyfills.js:3942:17 [angular]
    at new ZoneAwarePromise (zone-evergreen.js:876) [angular]
    at ExampleComponent.ngOnInit (example.component.ts:44) [angular]
    .....

Chúng ta có thể thấy rõ rằng lỗi không được xử lý đã được kích hoạt bởi một ngOnInitvà cũng có thể xem tệp mã nguồn nào để tìm dòng mã vi phạm.

Điều gì xảy ra khi chúng ta sử dụng async/waittừ chối:

    public async ngOnInit() {
        const p = await new Promise((resolver, reject) => reject());
    }

Ở trên tạo ra dấu vết ngăn xếp sau:

core.js:6014 ERROR Error: Uncaught (in promise):
    at resolvePromise (zone-evergreen.js:797) [angular]
    at :4200/polyfills.js:3942:17 [angular]
    at rejected (tslib.es6.js:71) [angular]
    at Object.onInvoke (core.js:39699) [angular]
    at :4200/polyfills.js:4090:36 [angular]
    at Object.onInvokeTask (core.js:39680) [angular]
    at drainMicroTaskQueue (zone-evergreen.js:559) [<root>]

Chuyện gì đã xảy ra? Chúng tôi không có manh mối, vì dấu vết ngăn xếp nằm ngoài thành phần.

Tuy nhiên, bạn có thể bị cám dỗ để sử dụng những lời hứa và tránh sử dụng async / wait. Vì vậy, hãy xem điều gì sẽ xảy ra nếu một lời hứa bị từ chối sau a setTimeout().

    public ngOnInit() {
        const p = new Promise((resolver, reject) => {
            setTimeout(() => reject(), 1000);
        });
    }

Chúng tôi sẽ nhận được dấu vết ngăn xếp sau:

core.js:6014 ERROR Error: Uncaught (in promise): [object Undefined]
    at resolvePromise (zone-evergreen.js:797) [angular]
    at :4200/polyfills.js:3942:17 [angular]
    at :4200/app-module.js:21450:30 [angular]
    at Object.onInvokeTask (core.js:39680) [angular]
    at timer (zone-evergreen.js:2650) [<root>]

Một lần nữa, chúng tôi đã mất ngữ cảnh ở đây và không biết phải đi đâu để sửa lỗi.

Các thiết bị quan sát phải chịu các tác dụng phụ tương tự của việc xử lý lỗi, nhưng nhìn chung các thông báo lỗi có chất lượng tốt hơn . Nếu ai đó sử dụng throwError(new Error())các Lỗi đối tượng sẽ chứa một chồng dấu vết, và nếu bạn đang sử dụng HttpModulecác Lỗi đối tượng thường là một phản ứng Http đối tượng đó nói với bạn về các yêu cầu.

Vì vậy, đạo lý của câu chuyện ở đây: Bắt lỗi của bạn, sử dụng những thứ có thể quan sát được khi bạn có thể và không sử dụng async ngOnInit(), bởi vì nó sẽ quay trở lại ám ảnh bạn như một lỗi khó tìm và sửa.

25 hữu ích 3 bình luận chia sẻ
4

Tôi tự hỏi nhược điểm của một biểu thức hàm được gọi ngay lập tức là gì :

    ngOnInit () {
      (async () => {
        const data = await this.service.getData();
        this.data = this.modifyMyData(data);
      })();
    }

Đó là cách duy nhất tôi có thể tưởng tượng để làm cho nó hoạt động mà không cần khai báo ngOnInit()dưới dạng một asynchàm

4 hữu ích 3 bình luận chia sẻ
2

Bạn có thể sử dụng hàm rxjs of.

of(this.service.getData());

Chuyển đổi lời hứa thành một chuỗi có thể quan sát được.

2 hữu ích 2 bình luận chia sẻ
1

Nếu getData () trả về một giá trị có thể quan sát được, bạn có thể thay đổi nó thành một lời hứa và giải quyết lời hứa đó bằng take (1).

import { take } from 'rxjs/operators';

async ngOnInit(): Promise<any> {
  const data = await this.service.getData().pipe(take(1)).toPromise();
  this.data = this.modifyMyData(data);
}
1 hữu ích 1 bình luận chia sẻ
1

Tôi đã sử dụng thử bắt bên trong ngOnInit ():

async ngOnInit() {      
   try {           
       const user = await userService.getUser();
    } catch (error) {           
        console.error(error);       
    }    
} 

Sau đó, bạn nhận được một lỗi mô tả nhiều hơn và bạn có thể tìm thấy lỗi ở đâu

1 hữu ích 0 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ angular typescript asynchronous promise observable , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading