MarkForCheck () और detectChanges () के बीच क्या अंतर है


174

बीच क्या अंतर है ChangeDetectorRef.markForCheck()और ChangeDetectorRef.detectChanges()?

मुझे केवल एसओ के बीच अंतर के रूप में जानकारी मिलीNgZone.run() , लेकिन इन दोनों कार्यों के बीच नहीं।

केवल डॉक्टर के संदर्भ के उत्तर के लिए, कृपया कुछ व्यावहारिक परिदृश्यों को एक दूसरे के ऊपर चुनने के लिए स्पष्ट करें।



@ मीलाद आप कैसे जानते हैं कि उसने इसे ठुकरा दिया था? ऐसे बहुत से लोग हैं जो इस साइट का उपयोग करते हैं।
गुडबाय StackExchange

2
@FrankerZ, क्योंकि मैं लिख रहा था और मैंने डाउनवोट देखा और बाद में एक दूसरा सवाल यह कहते हुए अपडेट किया गया था कि "केवल डॉक्टर के संदर्भ के साथ जवाब के लिए, कृपया कुछ व्यावहारिक परिदृश्यों को एक दूसरे को चुनने के लिए स्पष्ट करें? यह स्पष्ट करने में मदद करेगा? मेरे मन में"।
मिलाद

3
डाउनवोट आपको मूल उत्तर को पूरा करने के लिए प्रोत्साहित करने के लिए था जो डॉक्स से कॉपी और पेस्ट किया गया था जो मैंने पहले ही देखा था। और यह काम किया! अब उत्तर में बहुत स्पष्टता है और यह स्वीकृत उत्तर है, धन्यवाद
संसद

3
क्या एक कुटिल योजना @ पारदर्शिता!
हंकोका

जवाबों:


234

डॉक्स से:

पता लगाना (): शून्य

परिवर्तन डिटेक्टर और उसके बच्चों की जाँच करता है।

इसका मतलब है, अगर कोई ऐसा मामला है जहां आपके मॉडल (आपकी कक्षा) के अंदर कोई भी चीज़ बदल गई है, लेकिन उसने दृश्य को प्रतिबिंबित नहीं किया है, तो आपको उन परिवर्तनों का पता लगाने (स्थानीय परिवर्तनों का पता लगाने) और दृश्य को अपडेट करने के लिए कोणीय को सूचित करने की आवश्यकता हो सकती है।

संभावित परिदृश्य हो सकते हैं:

1- चेंज डिटेक्टर को व्यू से अलग कर दिया जाता है (देखें डिटैच )

2- एक अपडेट हुआ है, लेकिन यह एंगुलर जोन के अंदर नहीं है, इसलिए, एंगुलर को इसके बारे में पता नहीं है।

जैसे जब किसी थर्ड पार्टी फंक्शन ने आपके मॉडल को अपडेट किया है और आप उसके बाद व्यू अपडेट करना चाहते हैं।

 someFunctionThatIsRunByAThirdPartyCode(){
     yourModel.text = "new text";
 }

क्योंकि यह कोड एंगुलर ज़ोन (शायद) के बाहर है, इसलिए आपको सबसे अधिक बदलावों का पता लगाने और दृश्य को अपडेट करने के लिए सुनिश्चित करने की आवश्यकता है, इस प्रकार:

 myFunction(){
   someFunctionThatIsRunByAThirdPartyCode();

   // Let's detect the changes that above function made to the model which Angular is not aware of.
    this.cd.detectChanges();
 }

नोट :

उपरोक्त कार्य करने के अन्य तरीके हैं, दूसरे शब्दों में, उस परिवर्तन को कोणीय परिवर्तन चक्र के अंदर लाने के अन्य तरीके हैं।

** आप उस थर्ड पार्टी फंक्शन को ज़ोन के अंदर लपेट सकते हैं।

 myFunction(){
   this.zone.run(this.someFunctionThatIsRunByAThirdPartyCode);
 }

** आप एक सेट टाइमआउट के अंदर फ़ंक्शन को लपेट सकते हैं:

myFunction(){
   setTimeout(this.someFunctionThatIsRunByAThirdPartyCode,0);
 }

3- ऐसे मामले भी हैं जहां आप मॉडल change detection cycleको समाप्त होने के बाद अपडेट करते हैं , जहां उन मामलों में आपको यह भयानक त्रुटि मिलती है:

"जाँच के बाद अभिव्यक्ति बदल गई है";

इसका आम तौर पर मतलब है (Angular2 भाषा से):

मैंने आपके मॉडल में एक परिवर्तन देखा, जो मेरे स्वीकृत तरीकों (घटनाओं, XHR अनुरोधों, सेटटाइमआउट और ...) के कारण हुआ था और फिर मैंने आपके दृश्य को अपडेट करने के लिए अपना परिवर्तन पता लगाया और मैंने इसे समाप्त कर दिया, लेकिन फिर एक और था आपके कोड में फ़ंक्शन जिसने मॉडल को फिर से अपडेट किया और मैं फिर से अपने परिवर्तन का पता लगाना नहीं चाहता, क्योंकि अब AngularJS जैसी कोई गंदी जाँच नहीं है: D और हमें एक तरफ़ा डेटा प्रवाह का उपयोग करना चाहिए!

आप निश्चित रूप से इस त्रुटि के पार आएंगे: पी।

इसे ठीक करने के कुछ तरीके:

1- उचित तरीका : सुनिश्चित करें कि अपडेट परिवर्तन का पता लगाने के चक्र के अंदर है (Angular2 अपडेट एक तरह से प्रवाह है जो एक बार होता है, उसके बाद मॉडल को अपडेट न करें और अपना कोड बेहतर स्थान / समय पर ले जाएं)।

2- आलसी रास्ता : कोणीय 2 को खुश करने के लिए उस अपडेट के बाद पताचेंज () चलाएं, यह निश्चित रूप से सबसे अच्छा तरीका नहीं है, लेकिन जैसा कि आपने पूछा कि संभावित परिदृश्य क्या हैं, यह उनमें से एक है।

इस तरह से आप कह रहे हैं: मुझे पूरी तरह से पता है कि आपने परिवर्तन का पता लगाया है, लेकिन मैं चाहता हूं कि आप इसे फिर से करें क्योंकि मुझे आपके द्वारा जाँच पूरी करने के बाद फ्लाई पर कुछ अपडेट करना था।

3- कोड को अंदर रखें setTimeout, क्योंकि setTimeoutज़ोन द्वारा पैच किया गया है और detectChangesइसके समाप्त होने के बाद चलेगा ।


डॉक्स से

markForCheck() : void

सभी ChangeDetectionStrategy पूर्वजों की जाँच के रूप में चिह्नित करता है।

यह ज्यादातर तब आवश्यक होता है जब आपके घटक का ChangeDetectionStrategy OnPush हो

OnPush का अर्थ है कि, यदि इनमें से कोई भी हुआ है, केवल परिवर्तन का पता लगाएं:

1- घटक के @inputs को पूरी तरह से एक नए मूल्य के साथ बदल दिया गया है, या बस डाल दिया जाए, तो @Input संपत्ति का संदर्भ पूरी तरह से बदल गया है।

यदि आपके घटक का ChangeDetectionStrategy OnPush है और फिर आपके पास है:

   var obj = {
     name:'Milad'
   };

और फिर आप इसे अपडेट / म्यूट करते हैं:

  obj.name = "a new name";

यह ओब्ज संदर्भ को अपडेट नहीं करेगा , इसलिए परिवर्तन का पता लगाने वाला नहीं है, इसलिए दृश्य अपडेट / म्यूटेशन को प्रतिबिंबित नहीं कर रहा है।

इस मामले में आपको मैन्युअल रूप से एंगुलर को देखने और अपडेट को देखने के लिए बताना होगा (markForCheck);

तो अगर आपने ऐसा किया है:

  obj.name = "a new name";

आपको यह करने की आवश्यकता है:

  this.cd.markForCheck();

बल्कि, नीचे चलाने के लिए परिवर्तन का पता लगाने का कारण होगा:

    obj = {
      name:"a new name"
    };

जिसने पिछले ओब्ज को पूरी तरह से एक नए के साथ बदल दिया {};

2- एक घटना को निकाल दिया गया है, जैसे एक क्लिक या कुछ चीज़ जैसे या किसी भी बच्चे के घटकों ने एक घटना का उत्सर्जन किया है।

जैसे घटनाएँ:

  • क्लिक करें
  • तनाव के स्थिति में
  • सदस्यता कार्यक्रम
  • आदि।

तो संक्षेप में:

  • का प्रयोग करें detectChanges()जब आप कोणीय के बाद मॉडल को नवीनीकृत किया है यह परिवर्तन का पता लगाने के समाप्त हो गया है, या अद्यतन कोणीय दुनिया में सभी पर नहीं किया गया है यदि।

  • markForCheck()यदि आप OnPush का उपयोग कर रहे हैं और आप ChangeDetectionStrategyकुछ डेटा को बदलकर बाईपास कर रहे हैं या आपने किसी सेटटाइमआउट के अंदर मॉडल को अपडेट किया है, तो इसका उपयोग करें ;


6
इसलिए यदि आप उस ओब्जेक्ट को म्यूट करते हैं, तो व्यू अपडेट नहीं किया जाता है, और भले ही आप डिटेक्शन चलाते हों, यह काम नहीं करने वाला है क्योंकि इसमें कोई बदलाव नहीं हुआ है - यह सच नहीं है। detectChangesअद्यतन देखें। इसे गहराई से देखें ।
मैक्स कोरसेटस्की

निष्कर्ष में मार्कफॉरचेक के बारे में, यह भी सटीक नहीं है। इस प्रश्न से यहाँ संशोधित उदाहरण है , यह OnPush और markForCheck के साथ ऑब्जेक्ट परिवर्तनों का पता नहीं लगाता है। अगर कोई OnPush रणनीति नहीं है , लेकिन एक ही उदाहरण काम करेगा
एस्टुस फ्लास्क

@Maximus, आपकी पहली टिप्पणी के बारे में, मैंने आपकी पोस्ट पढ़ी, इसके लिए धन्यवाद कि यह अच्छा था। लेकिन आपके स्पष्टीकरण में आप कह रहे हैं कि क्या रणनीति ऑनपश है, इसका मतलब है कि अगर this.cdMode === ChangeDetectorStatus.Checkedयह दृश्य को अपडेट नहीं करेगा, तो इसीलिए आप मार्कफेकचेक का उपयोग करेंगे।
मिलाद

और आपके लिंक को प्लंकर के संबंध में, दोनों उदाहरण मेरे लिए ठीक काम कर रहे हैं, मुझे नहीं पता कि आपका क्या मतलब है
मिलाद

@ मीलाद, वो टिप्पणियां @estus :) से आई हैं। मेरा होने वाला था detectChanges। और cdModeकोणीय में कोई नहीं है 4.x.x। मैं उस बारे में अपने लेख में लिखता हूं। ख़ुशी है की तुम्हे पसंद आया। मत भूलो कि आप इसे माध्यम पर सुझा सकते हैं या मेरा अनुसरण कर सकते हैं :)
मैक्स कोरसेटस्की

99

दोनों के बीच सबसे बड़ा अंतर यह है कि detectChanges()वास्तव में परिवर्तन का पता लगाने को markForCheck()ट्रिगर करता है , जबकि परिवर्तन का पता लगाने को ट्रिगर नहीं करता है।

detectChanges

यह उस घटक के पेड़ के लिए परिवर्तन का पता लगाने के लिए उपयोग किया जाता है जो उस घटक से शुरू होता है जिसे आप ट्रिगर detectChanges()करते हैं। इसलिए परिवर्तन का पता वर्तमान घटक और उसके सभी बच्चों के लिए चलेगा। कोणीय जड़ घटक वृक्ष के संदर्भ में रखता है ( ApplicationRefऔर जब कोई भी async ऑपरेशन होता है, तो यह रैपर के माध्यम से इस मूल घटक पर परिवर्तन का पता लगाता है tick():

@Injectable()
export class ApplicationRef_ extends ApplicationRef {
  ...
  tick(): void {
    if (this._runningTick) {
      throw new Error('ApplicationRef.tick is called recursively');
    }

    const scope = ApplicationRef_._tickScope();
    try {
      this._runningTick = true;
      this._views.forEach((view) => view.detectChanges()); <------------------

viewयहाँ मूल घटक दृश्य है। कई रूट घटक हो सकते हैं जैसा कि मैंने वर्णित किया है कि कई घटकों को बूटस्ट्रैपिंग के निहितार्थ क्या हैं

@मिल ने उन कारणों का वर्णन किया जिनके कारण आपको मैन्युअल रूप से परिवर्तन का पता लगाने की आवश्यकता हो सकती है।

markForCheck

जैसा कि मैंने कहा, यह आदमी परिवर्तन का पता लगाने को ट्रिगर नहीं करता है। यह बस वर्तमान घटक से रूट घटक के ऊपर की ओर जाता है और उनके दृश्य स्थिति को अपडेट करता है ChecksEnabled। यहाँ स्रोत कोड है:

export function markParentViewsForCheck(view: ViewData) {
  let currView: ViewData|null = view;
  while (currView) {
    if (currView.def.flags & ViewFlags.OnPush) {
      currView.state |= ViewState.ChecksEnabled;  <-----------------
    }
    currView = currView.viewContainerParent || currView.parent;
  }
}

घटक के लिए वास्तविक परिवर्तन का पता लगाना निर्धारित नहीं है, लेकिन जब यह भविष्य में होगा (या तो वर्तमान या अगले सीडी चक्र के हिस्से के रूप में) तो माता-पिता के घटक विचारों की जांच की जाएगी, भले ही उन्होंने परिवर्तन डिटेक्टरों को अलग कर दिया हो। चेंज डिटेक्टर्स रणनीति का इस्तेमाल करके cd.detach()या OnPushबदलकर या तो डिटेक्टरों को अलग किया जा सकता है । सभी मूल इवेंट हैंडलर चेक के लिए सभी मूल घटक विचारों को चिह्नित करते हैं।

इस दृष्टिकोण का उपयोग अक्सर ngDoCheckजीवनचक्र हुक में किया जाता है । आप अधिक पढ़ सकते हैं यदि आपको लगता ngDoCheckहै कि इसका मतलब है कि आपके घटक की जाँच की जा रही है - इस लेख को पढ़ें

अधिक जानकारी के लिए कोणीय में परिवर्तन का पता लगाने के लिए आपको जो कुछ भी जानना है , वह भी देखें।


1
क्यों पता लगाता है घटक और उसके बच्चों पर काम करता है जबकि घटक और पूर्वजों पर निशान लगाते हैं?
पाब्लो

@ पाब्लो, यह डिज़ाइन द्वारा है। मैं तर्क के साथ वास्तव में परिचित नहीं हूं
मैक्स कोरसेटस्की

@ AngularInDepth.com बहुत गहन प्रसंस्करण है, तो परिवर्तनशीलता UI को अवरुद्ध करता है?
ऊँचाई २५२५

1
@jerry, अनुशंसित दृष्टिकोण है कि एसिंक्स्ट पाइप का उपयोग किया जाए, जो आंतरिक रूप से सदस्यता को ट्रैक करता है और हर नए मूल्य ट्रिगर पर markForCheck। इसलिए यदि आप async पाइप का उपयोग नहीं कर रहे हैं, तो शायद यही आपको उपयोग करना चाहिए। हालाँकि, ध्यान रखें, कि परिवर्तन का पता लगाने के लिए कुछ async घटना के परिणामस्वरूप स्टोर अपडेट होना चाहिए। हमेशा ऐसा ही होता है। लेकिन अपवाद हैं। blog.angularindepth.com/…
Max Koretskyi

1
@MaxKoretskyiakaWizard उत्तर के लिए धन्यवाद। हां, स्टोर अपडेट ज्यादातर एक परिणाम के रूप में होता है या सेटिंग पहले से लागू होती है। और लाने के बाद .. लेकिन हम हमेशा async pipeसदस्यता के अंदर से उपयोग नहीं कर सकते हैं हमारे पास आमतौर पर कुछ चीजें होती हैं जैसे कि call setFromValues do some comparison.. और यदि हम asyncस्वयं कॉल करते हैं तो markForCheckक्या समस्या है? लेकिन फिर से हमारे पास ngOnInitअलग-अलग डेटा प्राप्त करने में आमतौर पर 2-3 या कभी-कभी अधिक चयनकर्ता होते हैं ... और हम markForCheckउन सभी को कॉल करते हैं .. क्या यह ठीक है?
जेरी

0

cd.detectChanges() वर्तमान घटक से अपने वंशजों के माध्यम से तुरंत परिवर्तन का पता लगाएगा।

cd.markForCheck()परिवर्तन का पता लगाने के लिए नहीं चलेंगे, लेकिन परिवर्तन का पता लगाने के लिए अपने पूर्वजों को चिह्नित करें। अगली बार परिवर्तन का पता लगाना कहीं भी चलता है, यह उन घटकों के लिए भी चलेगा जिन्हें चिह्नित किया गया था।

  • यदि आप बार-बार परिवर्तन की संख्या कम करना चाहते हैं, तो उपयोग कहा जाता है cd.markForCheck()। अक्सर, परिवर्तन कई घटकों को प्रभावित करते हैं और कहीं न कहीं परिवर्तन का पता लगाने को कहा जाएगा। आप अनिवार्य रूप से कह रहे हैं: चलो यह सुनिश्चित करें कि ऐसा होने पर यह घटक भी अपडेट हो जाए। (मेरे द्वारा लिखे गए प्रत्येक प्रोजेक्ट में दृश्य तुरंत अपडेट किया जाता है, लेकिन प्रत्येक यूनिट टेस्ट में नहीं)।
  • यदि आप निश्चित नहीं हैं कि वर्तमान में परिवर्तन का पता cd.detectChanges()नहीं चल रहा है, तो उपयोग करें । उस मामले में त्रुटि होगी। इसका शायद मतलब है कि आप पूर्वज घटक की स्थिति को संपादित करने की कोशिश कर रहे हैं, जो उन मान्यताओं के खिलाफ काम कर रहा है जो कि कोणीय परिवर्तन का पता लगाने के लिए तैयार किए गए हैं। cd.markForCheck()detectChanges()
  • यदि यह महत्वपूर्ण है कि दृश्य किसी अन्य कार्रवाई से पहले सिंक्रोनस को अपडेट करता है, तो उपयोग करें detectChanges()markForCheck()हो सकता है कि वास्तव में आपके विचार को समय पर अपडेट न किया जाए। उदाहरण के लिए, यूनिट परीक्षण कुछ आपके दृश्य को प्रभावित करता है, आपको मैन्युअल रूप से कॉल करने की आवश्यकता हो सकती है fixture.detectChanges()जब यह ऐप में ही आवश्यक नहीं था।
  • यदि आप वंशों की तुलना में अधिक पूर्वजों के साथ एक घटक में राज्य बदल रहे हैं, तो आप घटक पूर्वजों detectChanges()पर अनावश्यक रूप से परिवर्तन का पता लगाने के लिए नहीं चल रहे हैं, तो आप का उपयोग करके एक प्रदर्शन में वृद्धि हो सकती है ।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.