ใช้เพื่อรอ ... จากพร้อมกับ iterables แบบซิงโครนัส


11

MDN กล่าวว่า for await...ofมีสองกรณีใช้งาน:

for await...ofงบสร้างวงวนมากกว่า async iterable วัตถุเช่นเดียวกับ iterables ซิงค์, ...

ผมก็ตระหนักก่อนหน้านี้ของอดีต: async iterables Symbol.asyncIteratorใช้ แต่ตอนนี้ฉันสนใจตอนหลัง: สามารถซิงโครไนซ์ได้

รหัสต่อไปนี้ซ้ำผ่าน iterable ซิงโครนัส - อาร์เรย์ของคำสัญญา ดูเหมือนว่าจะปิดกั้นความสำเร็จในการปฏิบัติตามสัญญาแต่ละข้อ

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)

พฤติกรรมดูเหมือนจะคล้ายกับการรอคอยสัญญาในทางกลับกันตามตรรกะที่แสดงด้านล่าง การยืนยันนี้ถูกต้องหรือไม่

ฉันถามเพราะรูปแบบของรหัสนี้มีข้อผิดพลาดในการปฏิเสธการดักฟังPromise.allและPromise.allSettledหลีกเลี่ยงและดูเหมือนว่าแปลกสำหรับฉันที่รูปแบบนี้จะได้รับการสนับสนุนอย่างชัดเจนจากภาษา


2
คำถามของคุณคืออะไร ดูเหมือนว่าตัวอย่างที่คุณมอบให้ทำงาน
Sagi Rika

คำอธิบายของฉันเกี่ยวfor await... ofกับการทำซ้ำแบบซิงโครนัสถูกต้องและถ้าเป็นเช่นนั้นมันเป็นเรื่องสำคัญไหมที่รูปแบบนั้นสามารถปล่อยข้อผิดพลาดการปฏิเสธที่ไม่ได้จัดการได้หรือไม่?
เบ็นแอสตัน

"ถูกต้องหรือไม่" ไม่ใช่คำถาม "ถูกต้อง" คือสิ่งที่คุณพูด
Robert Harvey

คุณสามารถสาธิตผ่านรหัสเพื่อแจ้งข้อผิดพลาดในการปฏิเสธการจัดการที่คุณอธิบายไว้ได้หรือไม่?
Robert Harvey

รหัสสุดท้ายแสดงให้เห็นถึงมัน ความถูกต้องมีความหมายที่ชัดเจนในบริบทนี้เพราะฉันได้ให้รหัสเพื่ออธิบายสิ่งที่ฉันคิดว่ามันกำลังทำอยู่ หากพฤติกรรมตรงกับรหัสของฉันแสดงว่ารหัสของฉันถูกต้องมิฉะนั้นความเข้าใจของฉันจะไม่ถูกต้อง นอกจากนี้การสังเกต"แก้ไข" ก็เป็นสิ่งที่คุณพูด ไม่จริงอย่างชัดเจน ถูกต้องมีความหมายที่กำหนดไว้อย่างดีในบริบทนี้
เบ็นแอสตัน

คำตอบ:


4

ใช่มันแปลกและคุณไม่ควรทำเช่นนี้ อย่าอาร์เรย์ย้ำสัญญาจะนำไปสู่ตรงกับปัญหาที่ไม่สามารถจัดการ-ปฏิเสธที่คุณกล่าวถึง

เหตุใดจึงรองรับภาษานี้ เพื่อดำเนินการต่อด้วยความหมายที่เลอะเทอะสัญญา

คุณสามารถหาเหตุผลที่แน่นอนในความคิดเห็นของปัญหาที่กล่าวถึงข้อเสนอนี้ :

ฉันคิดว่าเราควรถอยกลับไปSymbol.iteratorเพราะความหมายของคำสัญญาในปัจจุบันของเราเกี่ยวกับการอนุญาตให้ซิงค์สิ่งต่าง ๆ เพื่อใช้เป็นสิ่งแบบซิงค์ คุณอาจเรียกสิ่งนี้ว่า "ความสะเพร่า" มันเป็นไปตาม ตรรกะของ @ น้ำบาดาลด้านบนแต่ฉันต้องการที่จะอธิบายรายละเอียดให้มากขึ้น

ความหมาย "การผูกมัด" ของ.thenทั้งหมดเกี่ยวกับเรื่องนี้ คุณสามารถส่งคืนสัญญาจาก.thenหรือค่าสเกลาร์ มันเหมือนกันหมด คุณเรียกว่า Promise.resolveไม่ห่อบางสิ่งในสัญญา แต่จะส่งบางสิ่งไปยังสัญญา - รับค่าแบบอะซิงโครนัสเมื่อคุณมีบางอย่างหรืออย่างอื่น

ความหมายของasyncและawaitทั้งหมดเกี่ยวกับการเลอะเทอะเช่นกัน คุณสามารถตบawaitนิพจน์ที่ไม่ได้สัญญาใด ๆ ในฟังก์ชั่น async และทุกอย่างทำงานได้ดีในลักษณะเดียวกันยกเว้นว่าคุณให้การควบคุมกับคิวงาน ในทำนองเดียวกันคุณสามารถ "ป้องกัน" วางasync สิ่งที่คุณต้องการตราบใดที่คุณawaitผล หากคุณมีฟังก์ชั่นที่ส่งคืนสัญญา - อะไรก็ตาม! คุณสามารถทำให้ asyncฟังก์ชั่นนั้นและจากมุมมองของผู้ใช้ไม่มีอะไรเปลี่ยนแปลง (แม้ว่าในทางเทคนิคแล้วคุณจะได้รับวัตถุสัญญาที่แตกต่างออกไป)

ตัววนซ้ำ Async และเครื่องกำเนิดควรทำงานในลักษณะเดียวกัน เช่นเดียวกับที่คุณสามารถรอค่าที่ไม่ได้สัญญาไว้โดยไม่ตั้งใจผู้ใช้ที่มีเหตุผลคาดว่าจะสามารถyield*ซิงค์ตัววนซ้ำภายในเครื่องกำเนิด async ได้ for awaitลูปควรคล้ายกัน "เพียงแค่ทำงาน" ถ้าผู้ใช้ทำเครื่องหมายวนรอบอย่างนั้นโดยคิดว่าพวกเขาอาจได้รับตัววนซ้ำแบบ async

ฉันคิดว่ามันคงจะเป็นเรื่องใหญ่ที่จะทำลายความคล้ายคลึงเหล่านี้ทั้งหมด มันจะทำซ้ำ async ตามหลักสรีรศาสตร์น้อยลง มาคุยกันเรื่องนี้ในครั้งต่อไปที่ผู้สร้าง / ซิงค์ซ้ำในวาระการประชุมที่ TC39


ขอบคุณ. เป็นเหตุการณ์ที่ปล่อยออกมาหรือเป็นข้อผิดพลาดชนิดอื่นจริง ๆ ? ฉันถามเพราะฉันคิดว่าเหตุการณ์เป็นส่วนหนึ่งของ WebAPI มีการปล่อยกิจกรรมที่ใช้ในรูปแบบที่คล้ายคลึงกันในส่วนอื่น ๆ ของข้อมูลจำเพาะหรือไม่
เบ็นแอสตัน

@ 52d6c6af คุณหมายถึงunhandledrejectionเหตุการณ์หรือไม่
Bergi

ใช่. เป็นเพียงการสกัดกั้น "ข้อผิดพลาด" ที่ฉันใช้window.addEventListener('unhandledrejection',...ในระยะสั้น: มันเป็นเพียงอินสแตนซ์เดียวที่ฉันสามารถนึกได้ว่าการปล่อยข้อผิดพลาดประเภทนี้โดย JavaScript ฉันเกือบจะผิดอย่างแน่นอนที่จะคิดเรื่องนี้อย่างไรก็ตาม ในที่สุด: การปล่อย "ข้อผิดพลาด" นี้มีความสำคัญมากกว่าการมีข้อความแสดงข้อผิดพลาดที่ไม่ต้องการในคอนโซลหรือไม่?
เบ็นแอสตัน

1
@ 52d6c6af ดูที่นี่และมีสำหรับวิธีการนี้จะระบุไว้ในความพยายามร่วมกันระหว่าง ECMAScript และ Web API รายละเอียด ไม่เหตุการณ์ไม่สำคัญเลยมันสายเกินไปแล้วเมื่อคุณได้รับสิ่งนี้ Afaics มันใช้สำหรับตรวจสอบข้อผิดพลาดฝั่งไคลเอ็นต์เท่านั้น
Bergi

ถ้ามันไม่สำคัญจริง ๆ คำแนะนำนั้นยังคง "อย่าทำซ้ำอาร์เรย์ของคำสัญญา" หรือค่อนข้าง "โปรดทราบว่านี่จะไม่แสดงพฤติกรรมที่ล้มเหลวอย่างรวดเร็วภายใต้สถานการณ์บางอย่าง" หรือไม่?
เบ็นแอสตัน

0

sadสัญญาไม่ได้เป็นawaitเอ็ดเมื่อมันล้มเหลว - ความต้องการรหัสที่จะเสร็จสิ้นรอก่อนที่จะสามารถเริ่มต้นในการรอคอยhappy สัญญาเป็นความล้มเหลวก่อนที่จะแก้ไข ( เป็นเครื่องมือที่เหมาะกับกรณีการใช้งานนี้)sadsadhappyPromise.all


1
ฉันรู้ว่า. ดังนั้นคำถามของฉัน ถ้าPromise.allเป็นทางออกที่ดีกว่าทำไมภาษารองรับไวยากรณ์นี้ for await...ofสามารถนำมาใช้อย่างง่ายดายเพียงระบุ iterables แบบอะซิงโครนัส แต่พวกเขาให้ความสำคัญกับมันเพื่อระบุ iterables แบบซิงโครนัส ทำไม?
เบ็นแอสตัน

1
อาฉันเข้าใจผิด เราจะถามว่าทำไมfor await ... ofยอมรับยอมรับ iterables? ฉันคิดว่าจะสนับสนุนเครื่องกำเนิดไฟฟ้าแบบซิงค์ซึ่งอาจส่งคืนรายการที่มีเงื่อนไข
Gershom

ใช่โดยเฉพาะอย่างยิ่งเมื่อมันปรากฏขึ้นเพื่อแนะนำหลุมพรางการปฏิเสธสายไฟ
เบ็นแอสตัน

ในความคิดของฉันความผิดพลาดมักจะเกิดขึ้นในการสร้างสัญญาและไม่รอทันที น่าเสียดายที่ความผิดพลาดนี้มักจะเป็นคุณสมบัติที่มีประโยชน์
Gershom
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.