ความแตกต่างระหว่าง $ evalAsync และ $ timeout ใน AngularJS คืออะไร


180

ฉันใช้ AngularJS มาระยะหนึ่งแล้วและพบว่าจำเป็นต้องใช้$ timeoutทุกครั้ง (ดูเหมือนจะเป็นปลั๊กอิน jQuery)

เมื่อเร็ว ๆ นี้ฉันพยายามทำความเข้าใจวงจรการแยกย่อยที่ดีขึ้นและลึกซึ้งขึ้นและฉันได้พบกับฟังก์ชัน$ evalAsync

ดูเหมือนว่าฟังก์ชั่นดังกล่าวจะให้ผลลัพธ์ที่คล้ายกัน$timeoutเพียงคุณเท่านั้นที่ไม่ได้ทำให้มันล่าช้า ทุกครั้งที่ฉันใช้$timeoutมันจะมีการหน่วงเวลาเป็น 0 ดังนั้นตอนนี้ฉันสงสัยว่าควรใช้$evalAsyncแทนหรือไม่

มีความแตกต่างพื้นฐานระหว่างสองหรือไม่ กรณีใดบ้างที่คุณจะใช้อีกแบบหนึ่ง ฉันต้องการรับความรู้สึกที่ดีขึ้นเมื่อใช้อันใด

คำตอบ:


263

ฉันเพิ่งตอบคำถามนี้เป็นหลักที่นี่: https://stackoverflow.com/a/17239084/215945 (คำตอบนั้นเชื่อมโยงไปยังการแลกเปลี่ยน Github กับ Misko)

เพื่อสรุป:

  • ถ้ารหัสถูกจัดคิวโดยใช้$ evalAsync จากคำสั่งควรรันหลังจาก Angular DOM ได้รับการจัดการ แต่ก่อนที่เบราว์เซอร์จะแสดงผล
  • ถ้ารหัสถูกจัดคิวโดยใช้$ evalAsync จากคอนโทรลเลอร์มันควรจะทำงานก่อน Angular ได้รับการจัดการโดย Angular (และก่อนที่เบราว์เซอร์จะแสดงผล) - คุณไม่ค่อยต้องการสิ่งนี้
  • หากรหัสถูกจัดคิวโดยใช้$ timeoutควรรันหลังจาก DOM ถูกจัดการโดย Angular และหลังจากเบราว์เซอร์แสดงผล (ซึ่งอาจทำให้เกิดการสั่นไหวในบางกรณี)

15
ขอบคุณสำหรับคำอธิบาย สิ่งหนึ่งที่ฉันไม่แน่ใจว่าฉันเข้าใจ ทำไมมันถึงสร้างความแตกต่างถ้าคุณโทร $ evalAsync จากคอนโทรลเลอร์หรือคำสั่ง? asyncQueue ไม่รู้ว่ามันถูกลงทะเบียนจากคอนโทรลเลอร์หรือไดเร็กทีฟมันแค่รอคิวบนขอบเขตปัจจุบัน มันต้องทำอย่างไรกับเมื่อสิ่งต่าง ๆ ทำงานในคอนโทรลเลอร์และคอนโทรลเลอร์? ฉันแค่อยากเข้าใจส่วนนั้น
dnc253

@ dnc253 ฉันไม่ได้ดูรหัส Angular ดังนั้นฉันไม่ทราบคำตอบสำหรับคำถาม (ดี) ของคุณ หวังว่าคนอื่นสามารถแสดงความคิดเห็น
Mark Rajcok

15
"จากคำสั่ง" หมายถึง "จากฟังก์ชันการเชื่อมโยงของคำสั่ง" หรือไม่ หรือว่าเป็นจริงของพฤติกรรมเมื่อดำเนินการจากลิงค์หรือวิธีการควบคุมของคำสั่งหรือไม่
SimplGy

5
อ๋อมันชัดเจนจริงๆว่า "จากคำสั่ง" และ "จากตัวควบคุม" หมายถึงที่นี่
หนาม̈

1
@MarkRajcok คุณช่วยอธิบายได้ที่นี่: ถ้ารหัสถูกจัดคิวโดยใช้ $ evalAsync จากคำสั่งมันควรจะทำงานหลังจาก Angular DOM ถูกจัดการโดย Angular - มันควรจะทำงานหลังจาก DOM ถูกจัดการโดยคำสั่งนี้หรือโดยคำสั่งอื่น ๆ ?
Max Koretskyi

59

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

  • $ timeout (callback)จะรอรอบการแยกย่อยปัจจุบัน (เช่นการอัปเดตเชิงมุมทุกรุ่นและ DOM) จากนั้นมันจะดำเนินการติดต่อกลับ - อาจส่งผลกระทบต่อโมเดลเชิงมุม - จากนั้นจะเปิดใช้งานเต็ม$applyรูท $ ขอบเขตและ redigest ทุกอย่าง

  • $ evalAsync (การเรียกกลับ)ในทางกลับกันจะเพิ่มการเรียกกลับไปยังรอบปัจจุบันหรือรอบย่อย ซึ่งหมายความว่าหากคุณอยู่ในวงจรย่อย (ตัวอย่างเช่นในฟังก์ชั่นที่เรียกจากng-clickคำสั่งบางส่วน) สิ่งนี้จะไม่รออะไรเลยรหัสจะถูกดำเนินการทันที หากคุณอยู่ในการโทรแบบอะซิงโครนัสตัวอย่างเช่น a setTimeoutรอบการสรุปใหม่ ( $apply) จะถูกเรียกใช้

ดังนั้นในแง่ของการแสดงจะเป็นการดีกว่าเสมอที่จะเรียก$evalAsyncเว้นแต่ว่ามันสำคัญสำหรับคุณว่ามุมมองนั้นทันสมัยก่อนที่จะเรียกใช้งานโค้ดของคุณตัวอย่างเช่นถ้าคุณต้องการ acces สำหรับแอ็ตทริบิวต์ DOm เช่นความกว้างองค์ประกอบ

หากคุณต้องการรายละเอียดเพิ่มเติมเกี่ยวกับความแตกต่างระหว่าง $ timeout, $ evalAsync, $ digest, $ Apply ฉันขอเชิญคุณอ่านคำตอบของฉันในคำถามอื่น: https://stackoverflow.com/a/23102223/1501926

นอกจากนี้โปรดอ่านเอกสารประกอบ :

$ evalAsync ไม่รับประกันว่าเมื่อใดที่นิพจน์จะถูกดำเนินการเฉพาะที่:

  • มันจะดำเนินการหลังจากฟังก์ชั่นที่กำหนดเวลาการประเมินผล (ควรก่อนการแสดงผล DOM)
  • อย่างน้อยหนึ่งรอบ $ แยกย่อยจะดำเนินการหลังจากการดำเนินการแสดงออก

หมายเหตุ: ถ้าฟังก์ชั่นนี้จะเรียกว่าด้านนอกของ $ ย่อยวงจรเป็น $ ใหม่แยกแยะวงจรจะกำหนด อย่างไรก็ตามขอแนะนำให้ใช้รหัสการโทรที่เปลี่ยนแปลงรูปแบบจากภายในการโทรแบบใช้ $ ซึ่งรวมถึงรหัสที่ประเมินผ่าน $ evalAsync


คุณช่วยอธิบายได้ไหมว่าเหตุใดจึงต้องใช้การหมดเวลา $ ถ้าฉันต้องการเข้าถึงแอตทริบิวต์ DOM บางตัว สมมติว่าถ้าฉันมี <table width = "{{x}}"> ไม่ฟังก์ชั่นการเฝ้าดูของ ng-bind อัปเดตแอตทริบิวต์ dom ในหน่วยความจำฉันเข้าใจว่ามันจะไม่มีโอกาสทาสีมุมมองจนกว่าวงจรย่อยจะออก
Sridhar Chidurala

2
@SridharChidurala เนื่องจาก DOM ("HTML") ได้รับการอัปเดตระหว่างรอบการสรุปคุณต้องรอจนกว่าจะเสร็จสิ้นก่อนจึงจะสามารถอ่าน mofifications ได้ อย่างไรก็ตามสิ่งนี้เป็นสิ่งที่ท้อใจของ Angular คุณควรอ่านxจากขอบเขตโดยตรงแทนที่จะมาจาก DOM ดังนั้นคุณไม่ต้องรออะไรอีกเลย นอกจากนี้คุณควรใช้ng-styleกับ css แทนwidthคุณสมบัติที่ล้าสมัย หากคุณต้องการความช่วยเหลือเพิ่มเติมโปรดเปิดคำถามใหม่ใน StackOverflow
floribon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.