$ appli () และ $ digest () เป็นแนวคิดหลักสองประการใน AngularJs แต่บางครั้งพวกเขาก็สับสน เพื่อที่จะเข้าใจว่า AngularJs ทำงานอย่างไรคุณต้องเข้าใจว่า $ Apply () และ $ digest () ทำงานอย่างไร บทความนี้มีวัตถุประสงค์เพื่ออธิบายสิ่งที่ $ appl () และ $ digest () คือและวิธีการใช้ในการเข้ารหัสทุกวัน
1. สำรวจ $ Apply () และ $ digest ()
1.1. ทำความเข้าใจการเชื่อมโยงข้อมูลสองทางและ $ watch ();
AngularJS ให้คุณสมบัติที่ยอดเยี่ยมมากที่เรียกว่าการเชื่อมข้อมูลแบบสองทางซึ่งง่ายขึ้นอย่างมากวิธีที่เราเขียนรหัสของเรา การเชื่อมโยงข้อมูลหมายความว่าเมื่อข้อมูลใด ๆ ในมุมมองเปลี่ยนแปลงการเปลี่ยนแปลงจะถูกป้อนกลับไปยังข้อมูลขอบเขตโดยอัตโนมัติซึ่งหมายความว่าโมเดลขอบเขตจะได้รับการปรับปรุงโดยอัตโนมัติ ในทำนองเดียวกันเมื่อโมเดลขอบเขตเปลี่ยนแปลงข้อมูลในมุมมองจะได้รับการอัปเดตเป็นค่าล่าสุด แล้ว AngularJs ทำสิ่งนี้ได้อย่างไร? เมื่อคุณเขียนนิพจน์เช่น {{amodel}} angularJS จะตั้งค่าตัวเฝ้าดูให้คุณในโมเดลขอบเขตซึ่งใช้เพื่ออัปเดตมุมมองเมื่อข้อมูลเปลี่ยนไป ผู้เฝ้าดูที่นี่เหมือนกับผู้เฝ้าดูที่คุณจะตั้งค่าใน AngularJS:
$ scope. $ watch ('amodel', ฟังก์ชั่น (newValue, oldValue) {// อัปเดต DOM ด้วย newValue});พารามิเตอร์ที่สองส่งผ่านไปยัง $ watch () เป็นฟังก์ชันการโทรกลับซึ่งจะถูกเรียกเมื่อค่าของการเปลี่ยนแปลงของ Amodel เมื่อ Amodel เปลี่ยนแปลงมันไม่ยากที่จะเข้าใจว่าฟังก์ชั่นการโทรกลับนี้จะถูกเรียกให้อัปเดตมุมมอง แต่ก็ยังมีปัญหาที่สำคัญมาก! AngularJs รู้ได้อย่างไรว่าจะเรียกใช้ฟังก์ชันการโทรกลับนี้เมื่อใด กล่าวอีกนัยหนึ่ง AngularJS เรียกฟังก์ชั่นการโทรกลับที่เกี่ยวข้องอย่างไรเมื่อรู้ว่า Amodel เปลี่ยนไปอย่างไร มันจะเรียกใช้ฟังก์ชั่นเป็นระยะเพื่อตรวจสอบว่าข้อมูลในโมเดลขอบเขตมีการเปลี่ยนแปลงหรือไม่? นั่นคือที่ที่ $ Digest Loop เข้ามา
ใน $ Digest Loop ผู้เฝ้าดูจะถูกไล่ออก เมื่อผู้เฝ้าดูถูกกระตุ้น AngularJS จะตรวจจับโมเดลขอบเขต หากมีการเปลี่ยนแปลงฟังก์ชันการโทรกลับที่เกี่ยวข้องกับผู้เฝ้าดูจะถูกเรียก ดังนั้นคำถามต่อไปคือ $ Digest Loop เริ่มต้นเมื่อใด
หลังจากโทรไปที่ $ SCOPE. $ digest (), $ digest loop เริ่มต้นขึ้น สมมติว่าคุณเปลี่ยนข้อมูลในขอบเขตในฟังก์ชั่นตัวจัดการที่สอดคล้องกับคำสั่ง NG-click, AngularJS จะทริกเกอร์ $ digest loop โดยอัตโนมัติโดยเรียก $ digest () เมื่อ $ digest loop เริ่มต้นมันจะกระตุ้นให้ผู้เฝ้าดูแต่ละคน ผู้เฝ้าดูเหล่านี้จะตรวจสอบว่าค่าโมเดลปัจจุบันในขอบเขตนั้นแตกต่างจากค่าโมเดลที่คำนวณครั้งสุดท้ายหรือไม่ หากแตกต่างกันฟังก์ชันการโทรกลับที่สอดคล้องกันจะถูกดำเนินการ ผลลัพธ์ของการเรียกใช้ฟังก์ชั่นนี้คือเนื้อหาของนิพจน์ในมุมมอง (หมายเหตุของนักแปล: เช่น {{amodel}}) จะได้รับการอัปเดต นอกเหนือจากคำสั่ง NG-click แล้วยังมีคำสั่งและบริการในตัวอื่น ๆ เพื่อให้คุณเปลี่ยนโมเดล (เช่น NG-Model, $ TIMEOUT ฯลฯ ) และทริกเกอร์ลูป Digest โดยอัตโนมัติ
จนถึงตอนนี้มันไม่เลว! อย่างไรก็ตามมีปัญหาเล็ก ๆ น้อย ๆ ในตัวอย่างข้างต้น AngularJS ไม่ได้เรียก $ digest () โดยตรง แต่เรียกว่า $ scope. $ appli () ซึ่งเรียก $ rootscope $ digest () ดังนั้นห่วง $ digest เริ่มต้นที่ $ rootscope ซึ่งจะเข้าถึงผู้เฝ้าดูขอบเขตเด็กทุกคน
หมายเหตุ: $ scope. $ appli () จะโทรไปที่ $ rootscope โดยอัตโนมัติ $ digest ()
วิธี $ appl () มีสองรูปแบบ:
คนแรกจะยอมรับฟังก์ชั่นเป็นพารามิเตอร์ดำเนินการฟังก์ชันและทริกเกอร์ $ digest loop
ประเภทที่สองจะไม่ยอมรับพารามิเตอร์ใด ๆ และเพียงแค่ทริกเกอร์ $ digest loop เราจะเห็นทันทีว่าทำไมรูปแบบแรกจึงดีกว่า
1.2. เมื่อใดควรเรียกใช้วิธี $ apple () ด้วยตนเอง?
หาก AngularJS จะห่อรหัสของเราไว้ในฟังก์ชั่นและส่งผ่านใน $ Apply () เพื่อเริ่มต้น $ Digest Loop แล้วเราจะต้องเรียกวิธีการใช้ $ () ด้วยตนเองเมื่อใด ในความเป็นจริง AngularJS มีข้อกำหนดที่ชัดเจนมากสำหรับสิ่งนี้ว่ามันเป็นหน้าที่เฉพาะในการตอบสนองต่อการเปลี่ยนแปลงที่เกิดขึ้นโดยอัตโนมัติในบริบท AngularJS (เช่นการเปลี่ยนแปลงโมเดลที่เกิดขึ้นในวิธี $ Apply ()) นี่คือวิธีที่ Directive ในตัวของ AngularJS ทำดังนั้นการเปลี่ยนแปลงแบบจำลองใด ๆ จะสะท้อนให้เห็นในมุมมอง อย่างไรก็ตามหากคุณแก้ไขโมเดลที่ใดก็ได้นอกบริบท AngularJS คุณต้องแจ้ง AngularJS โดยโทรไปที่ $ Apply () ด้วยตนเอง มันเหมือนกับการบอก AngularJs ว่าคุณได้ปรับเปลี่ยนบางรุ่นและหวังว่า AngularJS สามารถช่วยให้คุณทริกเกอร์ผู้เฝ้าดูตอบสนองได้อย่างถูกต้อง
ตัวอย่างเช่นหากคุณใช้ SetTimeOut () ใน JavaScript เพื่ออัปเดตโมเดลขอบเขตดังนั้น AngularJS ก็ไม่มีทางรู้ว่าคุณมีอะไรเปลี่ยนแปลง ในกรณีนี้เป็นความรับผิดชอบของคุณในการโทร $ Apply () และเรียกใช้ห่วง $ digest โดยโทรหามัน ในทำนองเดียวกันหากคุณมีคำสั่งให้ตั้งค่าฟังเหตุการณ์ DOM และแก้ไขบางรุ่นในผู้ฟังนั้นคุณต้องโทรไปที่ $ Apply () ด้วยตนเองเพื่อให้แน่ใจว่าการเปลี่ยนแปลงจะสะท้อนให้เห็นอย่างถูกต้องในมุมมอง
ลองดูตัวอย่าง เข้าร่วมคุณมีหน้าเว็บที่เมื่อโหลดหน้าเว็บคุณต้องการแสดงข้อความหลังจากสองวินาที การใช้งานของคุณอาจมีลักษณะเช่นนี้:
html:
<body ng-app = "myapp"> <div ng-controller = "MessageController"> ข้อความล่าช้า: {{message}} </div> </body>JavaScript:
/ * เกิดอะไรขึ้นโดยไม่ต้องใช้ $ () */ angular.module ('myapp', []). คอนโทรลเลอร์ ('MessageController', ฟังก์ชั่น ($ scope) {$ scope.getMessage = function () {settimeout (function () {$ scope.message = ' } $ scope.getMessage ();});ด้วยการเรียกใช้ตัวอย่างนี้คุณจะเห็นว่าหลังจากสองวินาทีคอนโซลจะแสดงโมเดลที่อัปเดตอย่างไรก็ตามมุมมองจะไม่ได้รับการอัปเดต บางทีคุณอาจรู้เหตุผลอยู่แล้วนั่นคือเราลืมโทรหาวิธี $ apple () ดังนั้นเราจำเป็นต้องแก้ไข getMessage () ดังนี้:
/ * เกิดอะไรขึ้นกับ $ Apply */Angular.Module ('MyApp', []). คอนโทรลเลอร์ ('MessageController', ฟังก์ชั่น ($ scope) {$ scope.getMessage = function () {settimeout (function () {$ scope. $ scope.message);หากคุณเรียกใช้ตัวอย่างด้านบนคุณจะเห็นว่ามุมมองจะได้รับการอัปเดตหลังจากสองวินาที การเปลี่ยนแปลงเพียงอย่างเดียวคือตอนนี้รหัสของเราถูกห่อเป็น $ SCOPE $ APPLE () ซึ่งจะทริกเกอร์ $ ROOTSCOPE โดยอัตโนมัติ $ DIGEST () เพื่อให้ผู้เฝ้าดูถูกเรียกใช้เพื่ออัปเดตมุมมอง
หมายเหตุ: โดยวิธีการที่คุณควรใช้บริการ $ timeout แทน settimeout () เพราะอดีตจะเรียก $ appic () สำหรับคุณดังนั้นคุณไม่จำเป็นต้องเรียกมันด้วยตนเอง
นอกจากนี้โปรดทราบว่าในรหัสข้างต้นคุณสามารถโทรหา $ apple () ด้วยตนเองโดยไม่ต้องแก้ไขพารามิเตอร์หลังจากแก้ไขโมเดลเช่นเดียวกับต่อไปนี้:
$ scope.getMessage = function () {settimeout (function () {$ scope.message = 'ดึงหลังจากสองวินาที'; console.log ('ข้อความ:' + $ scope.message); $ scope. $ ใช้ (); -รหัสด้านบนใช้รูปแบบที่สองของ $ apple () นั่นคือแบบฟอร์มที่ไม่มีพารามิเตอร์ เป็นสิ่งสำคัญที่ต้องจำไว้ว่าคุณควรใช้วิธี $ Apply () ที่ใช้ฟังก์ชันเป็นพารามิเตอร์ นี่เป็นเพราะเมื่อคุณส่งฟังก์ชั่นไปยัง $ apple () ฟังก์ชั่นจะถูกห่อเป็นลอง ... บล็อกจับดังนั้นเมื่อมีข้อยกเว้นเกิดขึ้นข้อยกเว้นจะถูกประมวลผลโดยบริการ $ exceptionhandler
สถานการณ์ของการใช้ $ Apply () มีดังนี้:
•โดยปกติคุณสามารถโทรไปที่ $ Apply () ตามคำสั่งใด ๆ ที่จัดทำโดย Angular ที่สามารถใช้ในมุมมอง คำสั่ง NG- [Event] ทั้งหมด (เช่น NG-CLICK, NG-KEYPRESS) จะโทรไปที่ $ Apply ()
•นอกจากนี้คุณยังสามารถพึ่งพาชุดของบริการในตัวเชิงมุมเพื่อเรียก $ digest () ตัวอย่างเช่นบริการ $ http จะโทรไปที่ $ apple () หลังจากคำขอ XHR เสร็จสมบูรณ์และค่าคืนการอัปเดตจะถูกทริกเกอร์
•เมื่อใดก็ตามที่เราจัดการกับเหตุการณ์ด้วยตนเองให้ใช้เฟรมเวิร์กของบุคคลที่สาม (เช่น jQuery, Facebook API) หรือการโทรออก () เราสามารถใช้ฟังก์ชั่น $ apple () เพื่อให้การส่งคืนเชิงมุม
โทร setTimeout ():
<! doctype html> <html ng-app = "myapp"> <head> <title> $ scope. $ ใช้ () การใช้งาน </title> <meta charset = "utf-8"> <สคริปต์ src = "http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"> </script> </head> <body> <div id = "div1" ng-controller = "mytext"> <div> value = "jQuery-event"> </input> </div> </body> </html> <script type = "text/javascript"> var mymodule = angular.module ('myapp', []); myModule.Controller ("mytext", ฟังก์ชั่น ($ scope) {$ scope.text = "สถานที่"; settimeout (ฟังก์ชั่น () {$ scope.text = "ค่าที่กำหนดหลังจากหมดเวลา"; $ scope. $ ใช้ (); // การตรวจจับค่าสกปรก); </script>ใช้เฟรมเวิร์กของบุคคลที่สาม (เช่น JQuery, Facebook API):
<! doctype html> <html ng-app = "myapp"> <head> <title> $ scope. $ ใช้ () การใช้งาน </title> <meta charset = "utf-8"> <script src = "https://cdn.jsdelivr.net/jquery/3.1.1.1.1.1.1.1.1.1. src = "http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"> </script> <body> <div id = "div1" ng-controller = "mytext"> <div> {{text} value = "jQuery-event"> </input> </div> </body> </html> <script type = "text/javascript"> var mymodule = angular.module ('myapp', []); myModule.Controller ("mytext", ฟังก์ชั่น ($ scope) {$ scope.text = "สถานที่";}); $ (function () {$ ("#btn") คลิก (ฟังก์ชั่น () {var $ scope = $ ("#btn"). scope (); $ scope.text = "ค่าที่ตั้งอยู่ใน jQuery"; $ scope. $ ใช้ ();});}) </script>1.3. $ Digest Loop จะทำงานกี่ครั้ง?
เมื่อ $ Digest Loop กำลังทำงานอยู่ผู้เฝ้าดูจะถูกดำเนินการเพื่อตรวจสอบว่าโมเดลในขอบเขตมีการเปลี่ยนแปลงหรือไม่ หากการเปลี่ยนแปลงเกิดขึ้นฟังก์ชันฟังที่เกี่ยวข้องจะถูกดำเนินการ สิ่งนี้เกี่ยวข้องกับปัญหาที่สำคัญ จะเป็นอย่างไรถ้าฟังก์ชั่นผู้ฟังจะแก้ไขโมเดลขอบเขต AngularJS จะจัดการกับสถานการณ์นี้ได้อย่างไร?
คำตอบคือ $ Digest Loop จะไม่ทำงานเพียงครั้งเดียว หลังจากลูปปัจจุบันสิ้นสุดลงมันจะดำเนินการลูปอื่นเพื่อตรวจสอบว่าโมเดลมีการเปลี่ยนแปลงหรือไม่ นี่คือการตรวจสอบสกปรกซึ่งใช้ในการจัดการการเปลี่ยนแปลงแบบจำลองที่อาจเกิดขึ้นเมื่อฟังก์ชั่นฟังฟัง ดังนั้นลูป $ Digest จะยังคงทำงานต่อไปจนกว่าโมเดลจะไม่เปลี่ยนแปลงอีกต่อไปหรือ $ Digest Loop ถึง 10 ครั้ง ดังนั้นพยายามอย่าแก้ไขโมเดลในฟังก์ชั่นผู้ฟังให้มากที่สุด
หมายเหตุ: $ Digest Loop จะทำงานอย่างน้อยสองครั้งแม้ว่าจะไม่มีการเปลี่ยนแปลงรุ่นในฟังก์ชั่นผู้ฟังก็ตาม ตามที่กล่าวไว้ข้างต้นมันจะทำงานอีกครั้งเพื่อให้แน่ใจว่าโมเดลจะไม่เปลี่ยนแปลง
บทสรุป
สิ่งที่สำคัญที่สุดที่ต้องจำไว้คือ AngularJs สามารถตรวจจับการดัดแปลงของคุณเป็นแบบจำลองได้หรือไม่ หากไม่สามารถตรวจพบได้คุณจะต้องโทรไปที่ $ Apply () ด้วยตนเอง
หากคุณมีคำถามใด ๆ โปรดฝากข้อความถึงฉันและบรรณาธิการจะตอบกลับทุกคนในเวลา ขอบคุณมากสำหรับการสนับสนุนเว็บไซต์ Wulin.com!