Sử dụng để chờ đợi với các vòng lặp đồng bộ


11

MDN cho biết for await...of có hai trường hợp sử dụng:

Câu for await...oflệnh tạo ra một vòng lặp lặp qua các đối tượng lặp không đồng bộ cũng như trên các vòng lặp đồng bộ hóa, ...

Trước đây tôi đã biết về cái trước: async iterables bằng cách sử dụng Symbol.asyncIterator. Nhưng bây giờ tôi quan tâm đến cái sau: iterables đồng bộ.

Đoạn mã sau lặp lại qua một lần lặp đồng bộ - một mảng các lời hứa. Nó xuất hiện để chặn progess về việc thực hiện từng lời hứa.

async function asyncFunction() {
    try {
        const happy = new Promise((resolve)=>setTimeout(()=>resolve('happy'), 1000))
        const sad = new Promise((_,reject)=>setTimeout(()=>reject('sad')))
        const promises = [happy, sad]
        for await(const item of promises) {
            console.log(item)
        }
    } catch (err) {
        console.log(`an error occurred:`, err)
    }
}

asyncFunction() // "happy, an error occurred: sad" (printed in quick succession, after about 5 seconds)

Hành vi có vẻ giống như chờ đợi lần lượt từng lời hứa, theo logic được hiển thị bên dưới. Là khẳng định này là chính xác?

Tôi hỏi bởi vì mẫu mã này có một cạm bẫy từ chối ngầm ẩn Promise.allPromise.allSettledtránh, và có vẻ lạ đối với tôi rằng mẫu này sẽ được ngôn ngữ hỗ trợ rõ ràng.


2
Chính xác câu hỏi của bạn là gì? Có vẻ như các ví dụ bạn đã cung cấp công việc
Sagi Rika

Là mô tả của tôi for await... ofvới các lần lặp đồng bộ, chính xác, và nếu vậy, liệu mô hình đó có thể phát ra các lỗi từ chối không được xử lý không?
Ben Aston

"Có đúng không" không phải là một câu hỏi. "Chính xác" là bất cứ điều gì bạn nói nó là.
Robert Harvey

Bạn có thể chứng minh qua mã phát ra các lỗi từ chối chưa được xử lý mà bạn đã mô tả không?
Robert Harvey

Mã cuối cùng chứng minh điều đó. Correct có một ý nghĩa được xác định rõ trong ngữ cảnh này bởi vì tôi đã cung cấp mã để mô tả những gì tôi nghĩ nó đang làm. Nếu hành vi phù hợp với mã của tôi, thì mã của tôi là chính xác, nếu không thì sự hiểu biết của tôi là không chính xác. Ngoài ra, quan sát "Chính xác" là bất cứ điều gì bạn nói nó là. rõ ràng là không đúng sự thật. Đúng có một ý nghĩa được xác định rõ trong bối cảnh này.
Ben Aston

Câu trả lời:


4

Vâng, nó là lạ, và bạn không nên làm điều này. Đừng mảng lặp của lời hứa, nó dẫn chính xác cho vấn đề unhandled-từ chối bạn đề cập đến .

Vậy tại sao điều này được hỗ trợ trong ngôn ngữ? Để tiếp tục với ngữ nghĩa lời hứa cẩu thả.

Bạn có thể tìm thấy lý do chính xác trong bình luận này về vấn đề thảo luận về phần này của đề xuất :

Tôi nghĩ rằng chúng ta nên quay trở lại Symbol.iteratorbởi vì ngữ nghĩa Promise hiện tại của chúng ta đều hướng đến việc cho phép những thứ đồng bộ hóa được sử dụng như những thứ không đồng bộ. Bạn có thể gọi đây là "sự cẩu thả". Nó tuân theo logic của nước ngầm ở trên , nhưng tôi chỉ muốn đánh vần các điểm tương đồng chi tiết hơn.

Các ngữ nghĩa "chuỗi" .thenlà tất cả về điều này. Bạn có thể trả về một Promise từ .thenhoặc giá trị vô hướng; tất cả đều giống nhau Bạn gọi Promise.resolvekhông phải để bọc một cái gì đó trong một Lời hứa, mà là để gửi một cái gì đó cho một Lời hứa - nhận được một giá trị không đồng bộ khi bạn có thứ gì đó hoặc thứ khác.

Các ngữ nghĩa của asyncawaittất cả là về cẩu thả là tốt. Bạn có thể tát awaitvào bất kỳ biểu thức không hứa hẹn nào trong hàm async và mọi thứ đều hoạt động tốt, chính xác theo cùng một cách, ngoại trừ việc bạn nhường quyền kiểm soát cho hàng đợi công việc. Tương tự như vậy, bạn có thể "phòng thủ" đặt async xung quanh bất cứ điều gì bạn muốn, miễn là awaitkết quả của bạn. Nếu bạn có một chức năng trả về một Promise - bất cứ điều gì! bạn có thể làm cho asyncchức năng đó và, từ góc độ người dùng, không có gì thay đổi (ngay cả khi, về mặt kỹ thuật, bạn nhận được một đối tượng Promise khác).

Các trình lặp và bộ tạo Async nên hoạt động theo cùng một cách. Giống như bạn có thể chờ đợi một giá trị, vô tình, không phải là một Promise, một người dùng hợp lý sẽ mong đợi có thể có yield*một trình lặp đồng bộ hóa trong một trình tạo không đồng bộ. for awaitcác vòng lặp sẽ tương tự "chỉ hoạt động" nếu người dùng đánh dấu một cách chắc chắn một vòng lặp theo cách đó, nghĩ rằng họ có thể đang nhận được một trình lặp không đồng bộ.

Tôi nghĩ rằng nó sẽ là một vấn đề lớn để phá vỡ tất cả những tương đồng. Nó sẽ làm cho các trình lặp async ít tiện dụng hơn. Chúng ta hãy thảo luận về điều này vào lần tới khi các trình tạo / lặp không đồng bộ xuất hiện trong chương trình nghị sự tại TC39.


Cảm ơn bạn. Là một sự kiện phát ra, hoặc nó thực sự là một loại lỗi khác? Tôi hỏi vì tôi nghĩ các sự kiện là một phần của WebAPI. Là phát xạ của các sự kiện được sử dụng theo cách tương tự, trong các phần khác của thông số kỹ thuật?
Ben Aston

@ 52d6c6af Bạn đang đề cập đến các unhandledrejectionsự kiện?
Bergi

Đúng. Đó chỉ là để ngăn chặn "lỗi" mà tôi đã sử dụng window.addEventListener('unhandledrejection',...Tóm lại: đó là trường hợp duy nhất tôi có thể nghĩ đến, về loại phát xạ lỗi này bằng JavaScript. Tôi gần như chắc chắn sai khi nghĩ điều này, tuy nhiên. Cuối cùng: việc phát tán "lỗi" này có thực sự quan trọng ngoài việc có một thông báo lỗi không mong muốn trong bảng điều khiển không?
Ben Aston

1
@ 52d6c6af Xem tại đâyở đó để biết cách thức này được chỉ định trong nỗ lực chung giữa thông số kỹ thuật ECMAScript và API Web. Không, sự kiện không thực sự quan trọng, đã quá muộn khi bạn nhận được điều này. Afaics, nó chỉ được sử dụng để theo dõi lỗi phía khách hàng.
Bergi

Nếu nó không thực sự quan trọng, thì lời khuyên vẫn là "không lặp lại các mảng lời hứa" hay là "lưu ý rằng điều này không thể hiện hành vi thất bại trong một số trường hợp"?
Ben Aston

0

Các sadlời hứa không được awaited khi nó không thành công - đó là nhu cầu mã để hoàn thành chờ đợi vào happytrước khi nó có thể bắt đầu chờ đợi sad. Các sadlời hứa là không trước khi happygiải quyết. ( Promise.alllà một công cụ phù hợp hơn với trường hợp sử dụng này)


1
Tôi biết. Do đó câu hỏi của tôi. Nếu Promise.alllà một giải pháp tốt hơn, tại sao ngôn ngữ phục vụ cho cú pháp này? for await...ofcó thể dễ dàng được thực hiện để chỉ đơn giản là liệt kê các lần lặp không đồng bộ. Nhưng họ đã phục vụ cho nó để liệt kê các lần lặp đồng bộ (nhưng với một cạm bẫy (dường như?)). Tại sao?
Ben Aston

1
À, tôi hiểu lầm rồi. Có phải chúng ta hỏi tại sao for await ... ofchấp nhận lặp lại đồng bộ? Tôi tưởng tượng để hỗ trợ các trình tạo async có điều kiện có thể trả về các mục đồng bộ.
Gershom

Vâng, đặc biệt là do nó xuất hiện để giới thiệu một cạm bẫy từ chối dây.
Ben Aston

Theo tôi, cạm bẫy nói chung là nhiều hơn trong việc tạo ra một lời hứa, và không chờ đợi nó ngay lập tức. Thật không may, cạm bẫy này cũng thường là một tính năng rất hữu ích.
Gershom
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.