รูปแบบที่ถูกต้องสำหรับ Promise.defer คืออะไร?

ฉันใช้ TypeScript และ async/await เพื่อแสดงเวิร์กโฟลว์แบบอะซิงโครนัส ส่วนหนึ่งของขั้นตอนการทำงานนั้นคือการโทรหาพนักงานเว็บและดำเนินการต่อเมื่อมีการโทรกลับพร้อมผลลัพธ์

ใน C# ฉันจะสร้าง TaskCompletionSource, await ของมัน Task และที่อื่นๆ ในโค้ดจะเรียก SetResult เพื่อแก้ไข TaskCompletionSource

ฉันสามารถทำสิ่งเดียวกันใน JavaScript ได้ด้วยการเริ่มต้นอ็อบเจ็กต์ Deferrer โดยใช้ Promise.defer(), awaiting ของมัน Promise และที่อื่นๆ ใน window.onmessage Listener จะเรียกใช้เมธอด resolve (หรือ reject) เพื่อให้เวิร์กโฟลว์แบบอะซิงโครนัสดำเนินต่อไป

ฟังดูดี แต่ MDN บอกว่า defer ล้าสมัย วิธีแก้ปัญหาที่เสนอสำหรับการใช้ตัวสร้าง Promise ซึ่งให้ผู้รับมอบสิทธิ์ทำงานและการเรียกใช้เมธอด resolve/reject ไม่ได้ผลสำหรับฉัน เนื่องจากตรรกะนั้นอาจไม่สามารถเข้าถึงได้ ฉันแค่ต้องการให้ object โทร resolve หรือ reject บน ในขอบเขตคำศัพท์ที่แตกต่างไปจากเดิมอย่างสิ้นเชิง ฉันไม่สามารถทำเช่นนั้นกับฟังก์ชันนั้นได้

มีตัวช่วยที่เข้ากันได้ย้อนหลังและส่งต่อ ที่ให้วัตถุดังกล่าวแก่ฉันโดยการผูกฟังก์ชัน resolve และ reject ที่ฉันสามารถใช้ได้โดยไม่ต้องเปลี่ยนซีแมนทิกส์ของโค้ด แต่นี่เป็นการปฏิบัติที่ไม่ดีหรือไม่? มีรูปแบบที่ได้รับการยอมรับและดีกว่าหรือไม่? สำนวนที่เทียบเท่ากับ TaskCompletionSource ใน JavaScript คืออะไร


person Tomáš Hübelbauer    schedule 01.08.2016    source แหล่งที่มา


คำตอบ (1)


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

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

ต่อไปนี้เป็นการใช้งาน Deferred ง่ายๆ อีกประการหนึ่งที่เข้ากันได้ทั้งแบบย้อนหลังและส่งต่อ:

เหตุใด Constructor ของ Promise จึงจำเป็นต้องมีตัวดำเนินการ

แต่นี่เป็นการปฏิบัติที่ไม่ดีหรือไม่?

ฉันรู้ว่ามีพวกเจ้าระเบียบบางคนที่คิดว่าคุณไม่ควรทำอย่างนี้ แต่ฉันบอกได้เลยว่ามันเป็นแนวทางปฏิบัติที่ดีอย่างยิ่ง หากคุณแน่ใจว่ามันเป็นวิธีที่สะอาดและง่ายที่สุดในการติดตั้งโค้ดของคุณ และการใช้งานมันด้วยการเรียกกลับตัวดำเนินการคอนสตรัคเตอร์ของ Promise ทั่วไปนั้นไม่สามารถทำได้จริง มีผู้ที่ต้องการใช้ deferred โดยไม่ต้องพยายามหรือเรียนรู้ตัวสร้าง / ตัวดำเนินการตามสัญญาและนั่นจะไม่ใช่แนวปฏิบัติที่ดี ด้วยเหตุผลหลายประการ ควรใช้ตัวสร้างสัญญาเมื่อใช้งานได้จริง

เหตุผลสำคัญประการหนึ่งที่แนะนำให้ใช้ Constructor ของสัญญาก็คือโค้ดเฉพาะของสัญญาทั้งหมดในฟังก์ชันการเรียกกลับของตัวดำเนินการคือ "throw-safe" หากมีข้อยกเว้นเกิดขึ้นในโค้ดนั้น โค้ดนั้นจะถูกตรวจจับและปฏิเสธสัญญาโดยอัตโนมัติ (ซึ่งเป็นสิ่งที่ดี) เมื่อคุณใช้การเลื่อนออกไปและมีโค้ดจำนวนมากที่จัดการสัญญานอกเหนือจากการโทรกลับนั้น มันก็จะไม่ปลอดภัยโดยอัตโนมัติ ในความเป็นจริง โค้ดของคุณยังสามารถส่งพร้อมกันได้ ซึ่งเป็นฝันร้ายสำหรับผู้โทรที่ต้องป้องกัน คุณสามารถดูคำอธิบายของปัญหาดังกล่าวได้ที่นี่: https://stackoverflow.com/a/37657831/816620 ดังนั้น รูปแบบที่เลื่อนออกไปจึงไม่เป็นที่ต้องการ แต่ด้วยการป้องกันที่เหมาะสม ยังมีบางกรณี (โดยทั่วไปพบไม่บ่อย) ที่นำไปสู่การนำไปปฏิบัติที่สะอาดยิ่งขึ้น

มีรูปแบบที่ได้รับการยอมรับและดีกว่าหรือไม่?

แทบจะเป็นคำตอบเดียวกับข้างบนเลย การตั้งค่าคือการใช้ตัวสร้าง/ตัวดำเนินการของสัญญา แต่ในสถานการณ์ที่ไม่สามารถใช้งานได้จริง (โดยปกติแล้วส่วนต่างๆ ของโค้ดสร้างสัญญาแล้วแก้ไข/ปฏิเสธ) และไม่มีวิธีง่ายๆ ในการจัดระเบียบโค้ดใหม่เพื่อให้ทำงานได้ดีด้วย ตัวสร้าง / ตัวดำเนินการตามสัญญาดังนั้นวัตถุที่เลื่อนออกไปน่าจะเป็นการใช้งานที่ต้องการ โดยทั่วไปคุณควรพบว่าสถานการณ์เหล่านี้เกิดขึ้นไม่บ่อยนัก เพราะโดยส่วนใหญ่แล้วคุณสามารถจัดโครงสร้างโค้ดของคุณได้ ดังนั้นโค้ดชิ้นเดียวกันจึงเป็นการสร้างและแก้ไข/ปฏิเสธสัญญา และคุณไม่จำเป็นต้องมีการเลื่อนออกไป

TaskCompletionSource ที่เทียบเท่ากับสำนวนใน JavaScript คืออะไร

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

person jfriend00    schedule 01.08.2016
comment
นี่เป็นคำตอบที่น่าทึ่ง ขอบคุณที่สละเวลามาก ฉันจินตนาการไม่ออกว่าฉันจะสร้าง Promise เพื่อรอในหน้าต่างหลักและ resolve จาก ผู้ปฏิบัติงานเว็บ ได้อย่างไร (ไฟล์อื่นไม่น้อย!) ในขณะที่ใช้ตัวดำเนินการ Promise Constructor ดังนั้นฉันคิดว่า ฉันสบายดีที่ใช้ Deferred สำหรับสิ่งนี้ - person Tomáš Hübelbauer; 02.08.2016
comment
@ TomášHübelbauer - ในที่สุด webWorker จะต้องส่งข้อความไปยังเธรดหลักเพื่อสื่อสารกับมันใช่ไหม คุณสามารถให้ผู้ดำเนินการตามสัญญาฟังข้อความนั้นและแก้ไขสัญญาในตัวดำเนินการเมื่อได้รับข้อความได้หรือไม่ ฉันแค่เดาที่นี่เพราะฉันไม่เห็นรหัสจริงของคุณ - person jfriend00; 02.08.2016
comment
ลองคิดดูสิ ฉันสามารถฟังข้อความในการใช้งานตัวดำเนินการได้ แม้ว่าปัจจุบันตัวประมวลผลข้อความของฉันจะอยู่ที่ศูนย์กลาง และด้วยวิธีนี้ ฉันจะต้องแยกมันออกจากตัวดำเนินการแต่ละคน ฉันจะเล่นกับมัน บางทีฉันอาจมองข้ามบางสิ่งบางอย่างไป จะโพสต์คำถามหากฉันไม่มีความคิดหรือไม่แน่ใจ :) - person Tomáš Hübelbauer; 02.08.2016
comment
@ TomášHübelbauer - บ่อยครั้งที่ (แต่ไม่เสมอไป) รูปแบบการออกแบบตัวดำเนินการเพียงแค่ต้องคิดใหม่เกี่ยวกับวิธีการจัดโครงสร้างของโค้ดเพื่อใช้ประโยชน์จากมัน ขอให้โชคดี. - person jfriend00; 02.08.2016
comment
ฉันหลีกเลี่ยงมันมาตลอดเพราะฉันสร้างฟังก์ชัน callback ในทุกฟังก์ชัน jshint เตือนไม่ให้สร้างฟังก์ชันแบบไดนามิก นี่ไม่ใช่ข้อตกลงด้านประสิทธิภาพที่ยิ่งใหญ่ใช่ไหม นั่นเป็นเหตุผลว่าทำไมจึงแนะนำให้ใช้ new Promise(callback) เท่านั้น - person Noitidart; 19.08.2016
comment
@Noitidart - ในความคิดของฉัน jshint ทำให้คุณต้องหลีกเลี่ยงวิธีที่ดีกว่าในการเขียนโค้ด ตัวตรวจสอบโค้ดเหล่านี้ค่อนข้างโง่จริงๆ หากคุณสุ่มสี่สุ่มห้าทำตามที่พวกเขาพูด คุณจะหลุดออกจากแนวปฏิบัติที่ดีที่สุดในบางกรณี คุณต้องรู้ว่าคุณกำลังทำอะไรอยู่และเมื่อใดที่ควรเพิกเฉยต่อพวกเขา ฟังก์ชันอินไลน์ที่ไม่เปิดเผยตัวตนมีประโยชน์อย่างเหลือเชื่อใน Javascript และเป็นวิธีที่ดีที่สุดในการเขียนโค้ดอย่างชัดเจน ฉันจะไม่หลีกเลี่ยงพวกเขา jsHint อาจจะบ่นก็ต่อเมื่อคุณทำสิ่งนั้นแบบวนซ้ำ ซึ่งในกรณีนี้ฉันจะต้องดูโค้ดที่แน่นอนเพื่อที่จะรู้ว่าฉันจะแนะนำอะไร - person jfriend00; 19.08.2016