কৌণিক জেএস: ত্রুটি প্রতিরোধ করুন $ স্কোপ calling কল করার সময় ইতিমধ্যে প্রগতিতে ডাইজেস্ট $ প্রয়োগ ()


838

কৌণিকভাবে একটি অ্যাপ্লিকেশন তৈরি করার পরে আমি খুঁজে পাচ্ছি যে আমার পৃষ্ঠাটি ম্যানুয়ালি আমার স্কোপে আরও আপডেট করা দরকার।

এটি করার জন্য আমি জানতে পারি যে একমাত্র উপায় $apply()আমার নিয়ন্ত্রক এবং নির্দেশের সুযোগ থেকে কল করা। এটির সাথে সমস্যাটি হ'ল এটি কনসোলে একটি ত্রুটি নিক্ষেপ করে চলেছে যা পড়ে:

ত্রুটি: gest ডাইজেস্ট ইতিমধ্যে চলছে

কেউ কীভাবে এই ত্রুটিটি এড়াতে বা একই জিনিস অর্জন করতে পারে তবে ভিন্ন উপায়ে জানে?


34
এটি সত্যই হতাশার জিনিস যা আমাদের প্রয়োজন more আরও বেশি বেশি প্রয়োগ করা $
ওজেড

আমি কল করছি though কলব্যাকটিতে প্রয়োগ করেও আমি এই ত্রুটিটি পাচ্ছি। আমি তাদের সার্ভারগুলিতে ডেটা অ্যাক্সেস করতে একটি তৃতীয় পক্ষের লাইব্রেরিটি ব্যবহার করছি, তাই আমি $ HT-র সুবিধা নিতে পারি না বা চাই না যেহেতু আমাকে library http ব্যবহার করার জন্য তাদের লাইব্রেরিটি পুনরায় লিখতে হবে।
ট্রেভর

45
ব্যবহার$timeout()
ওনুর ইল্ডারিয়াম

6
$ টাইমআউট (এফএন) + 1 ব্যবহার করুন, এটি সমস্যার সমাধান করতে পারে,! $ সুযোগ $$ পর্বটি সেরা সমাধান নয়।
হুয়ে টান

1
কেবল কোড / কল স্কোপ মোড়ানো time সময়সীমার মধ্যে থেকে প্রয়োগ করুন (টাইমআউট নয়) এজেএক্স ফাংশন ($ http নয়) এবং ইভেন্টগুলি (নয় ng-*)। নিশ্চিত করুন, যদি আপনি একটি ফাংশন মধ্যে থেকে এটা আহ্বান করা হয় (সময়সীমার / Ajax / ঘটনা মাধ্যমে বলা হয় যে), যে এটা না আরো প্রাথমিকভাবে লোড চালানো হচ্ছে।
প্যাট্রিক

উত্তর:


660

এই নিদর্শনটি ব্যবহার করবেন না - এটি সমাধান হওয়ার চেয়ে আরও ত্রুটি সৃষ্টি করে। যদিও আপনি মনে করেন এটি কোনও কিছু স্থির করেছে, তা হয়নি।

$digestইতিমধ্যে চেক করে কোনও ইতিমধ্যে চলছে কিনা তা আপনি পরীক্ষা করতে পারেন $scope.$$phase

if(!$scope.$$phase) {
  //$digest or $apply
}

$scope.$$phaseফিরে আসবে "$digest"বা "$apply"একটি $digestবা $applyপ্রগতিতে রয়েছে। আমি বিশ্বাস করি যে এই রাজ্যের মধ্যে পার্থক্যটি হ'ল $digestবর্তমান ক্ষেত্র এবং এর শিশুদের ঘড়িগুলি প্রক্রিয়াকরণ করবে এবং সমস্ত স্কোপের $applyপর্যবেক্ষকদের প্রক্রিয়া করবে।

@ ডিএনসি 253 এর বক্তব্য, আপনি যদি নিজেকে কল করতে $digestবা $applyঘন ঘন নিজেকে খুঁজে পান তবে আপনি এটি ভুল করছেন। অ্যাংুলারের নাগালের বাইরে কোনও ডিওএম ইভেন্টের গুলি চালানোর ফলে যখন আমার স্কোপটির অবস্থা আপডেট করতে হয় তখন আমি সাধারণত আমার হজম করা দরকার বলে মনে করি। উদাহরণস্বরূপ, যখন কোনও টুইটার বুটস্ট্র্যাপ মডেলটি গোপন হয়ে যায়। কখনও কখনও যখন কোনও $digestঅগ্রগতি হয় তখন ডিওএম ইভেন্টটি জ্বলে ওঠে , কখনও কখনও তা ঘটে না। এজন্যই আমি এই চেকটি ব্যবহার করি।

আমি যদি কারও কিছু জানতে পারি তবে আরও ভাল উপায় জানতে আগ্রহী।


মন্তব্যগুলি থেকে: @ অ্যান্ডআডোটোই দ্বারা

angular.js এন্টি প্যাটার্নস

  1. করবেন না if (!$scope.$$phase) $scope.$apply(), এর অর্থ $scope.$apply()কল স্ট্যাকের মধ্যে আপনার পর্যাপ্ত পরিমাণ নেই।

230
আমার কাছে দেখে মনে হচ্ছে $ ডাইজেস্ট / $ প্রয়োগ করা উচিত এটি ডিফল্টরূপে করা উচিত
রায় ট্রুইলোভ

21
নোট করুন যে কিছু ক্ষেত্রে আমাকে এখনকার স্কোপ এবং রুট স্কোপটি যাচাই করতে হবে। আমি মূলটিতে $$ ধাপের জন্য একটি মান পাচ্ছি তবে আমার সুযোগে নয়। কোনও নির্দেশকের বিচ্ছিন্ন সুযোগের সাথে এটির কিছু করার কথা ভাবুন তবে ..
রায় ট্রুইলোভ

106
"করা বন্ধ করুন if (!$scope.$$phase) $scope.$apply()", github.com/angular/angular.js/wiki/Antti- প্যাটার্নস
andtoutoi

34
@ অ্যান্ডডোটাই: সম্মত; আপনার লিঙ্কটি এটি পরিষ্কার নয় এটি সমাধান নয়; তবে, "কল স্ট্যাকের ক্ষেত্রে আপনি যথেষ্ট উচ্চতায় নেই" এর অর্থ কী তা আমি অনিশ্চিত। আপনি কি জানেন এর মানে কি?
ট্রেভর

13
@ থ্রিড: অ্যারনফ্রস্টের উত্তর দেখুন। সঠিক উপায় হ'ল পরবর্তী চক্রের ডাইজেস্টকে ট্রিগার করতে ডিফার ব্যবহার করা। অন্যথায় ইভেন্টটি হারিয়ে যাবে এবং সুযোগটি একেবারেই আপডেট করবে না।
মারেক

663

এই বিষয়টিতে কৌণিক ছেলেদের সাথে সাম্প্রতিক আলোচনা থেকে: ভবিষ্যত-প্রমাণী কারণে, আপনার ব্যবহার করা উচিত নয়$$phase

এটি করার জন্য "ডান" উপায়টির জন্য চাপ দেওয়া হলে উত্তরটি বর্তমানে দেওয়া আছে

$timeout(function() {
  // anything you want can go here and will safely be run on the next digest.
})

ফেসবুক, গুগল, এবং টুইটার এপিআই, যা বিভিন্ন ডিগ্রীতে, কলব্যাকগুলি হস্তান্তর করে, মোড়ানোর জন্য কৌনিক পরিষেবাগুলি লেখার সময় আমি সম্প্রতি এটিতে প্রবেশ করি।

এখানে একটি পরিষেবার মধ্যে থেকে একটি উদাহরণ। (বংশবৃদ্ধির স্বার্থে, পরিষেবাটি বাকি - যা ভেরিয়েবল সেট করে, ইনজেকশনের $ সময়সীমা ইত্যাদি ছেড়ে যায় been)

window.gapi.client.load('oauth2', 'v2', function() {
    var request = window.gapi.client.oauth2.userinfo.get();
    request.execute(function(response) {
        // This happens outside of angular land, so wrap it in a timeout 
        // with an implied apply and blammo, we're in action.
        $timeout(function() {
            if(typeof(response['error']) !== 'undefined'){
                // If the google api sent us an error, reject the promise.
                deferred.reject(response);
            }else{
                // Resolve the promise with the whole response if ok.
                deferred.resolve(response);
            }
        });
    });
});

লক্ষ্য করুন $ সময়সীমার জন্য বিলম্ব যুক্তি ঐচ্ছিক এবং 0 ডিফল্ট যদি সেট করা না হবে ( $ সময়সীমার আহ্বান $ browser.defer যা যদি বিলম্ব সেট না করা হয় 0 ডিফল্ট )

কিছুটা স্বজ্ঞাত নয়, তবে এটি কৌনিকটি লেখার লোকদের উত্তর, সুতরাং এটি আমার পক্ষে যথেষ্ট ভাল!


5
আমি আমার নির্দেশাবলী এ অনেক বার ছুটেছি। রেডেক্টরটির জন্য একটি লিখছিল এবং এটি পুরোপুরি কার্যকর হয়ে উঠল। আমি ব্র্যাড গ্রিনের সাথে বৈঠকে ছিলাম এবং তিনি বলেছিলেন যে জেএসের নেটিভ পর্যবেক্ষণের ক্ষমতা এবং অভাবযুক্ত ব্রাউজারগুলির জন্য একটি পলিফিল ব্যবহার করে অ্যাঙ্গুলার ২.০ কোনও ডাইজেস্ট চক্র সহ বিশাল হবে be এই মুহুর্তে আমাদের আর এটি করার প্রয়োজন হবে না। :)
মাইকেল জে। ক্যালকিনস

গতকাল আমি এমন একটি সমস্যা দেখেছি যেখানে lec সময়সীমার মধ্যে selectize.refreshItems () কল করার কারণে ভয়ঙ্কর পুনরাবৃত্তির ডাইজেস্ট ত্রুটি ঘটেছে। কোন ধারণা কিভাবে যে হতে পারে?
i

3
আপনি যদি নেটিভের $timeoutপরিবর্তে ব্যবহার করেন তবে আপনি setTimeoutকেন নেটিভের $windowপরিবর্তে ব্যবহার করবেন না window?
লিগি

2
@ লিগি: এক্ষেত্রে ব্যবহারের $timeoutবিষয়টি এটি $timeoutনিশ্চিত করে যে কৌণিক স্কোপটি সঠিকভাবে আপডেট হয়েছে is যদি কোনও gest ডাইজেস্ট প্রগতিতে না থাকে তবে এটি একটি নতুন $ ডাইজেস্ট চালাতে পারে।
ভীতি

2
@ ওয়েবিসি এটি কোনও জিনিস নয়। যখন ফাংশনটির বডিটি $ টাইমআউট শেষ হয়ে যায় তখন প্রতিশ্রুতি ইতিমধ্যে সমাধান হয়ে যায়! এর একেবারে কোনও কারণ নেই cancelদস্তাবেজগুলি থেকে : "এর ফলস্বরূপ, প্রতিশ্রুতি প্রত্যাখ্যানের সাথে সমাধান করা হবে।" আপনি কোনও সমাধান প্রতিশ্রুতি সমাধান করতে পারবেন না। আপনার বাতিলকরণের ফলে কোনও ত্রুটি ঘটবে না, তবে এটি ইতিবাচক কিছুও করবে না।
ডেমোনেক্সমাচিনা

324

ডাইজেস্ট চক্রটি একটি সিঙ্ক্রোনাস কল। এটি সম্পন্ন না হওয়া পর্যন্ত এটি ব্রাউজারের ইভেন্ট লুপটিতে নিয়ন্ত্রণ দেয় না। এটি মোকাবেলা করার কয়েকটি উপায় রয়েছে। এটির সাথে মোকাবিলার সহজতম উপায় হ'ল বিল্ট-ইন টাইমআউট ব্যবহার করা এবং দ্বিতীয় উপায়টি হ'ল আপনি যদি আন্ডারস্কোর বা লোডাশ ব্যবহার করছেন (এবং আপনার হওয়া উচিত), নিম্নলিখিত কল করুন:

$timeout(function(){
    //any code in here will automatically have an apply run afterwards
});

বা আপনার যদি লোডাশ থাকে:

_.defer(function(){$scope.$apply();});

আমরা বেশ কয়েকটি কাজের চেষ্টা করেছি এবং আমরা আমাদের সমস্ত নিয়ন্ত্রক, নির্দেশিকা এবং এমনকি কিছু কারখানায় $ রুটস্কোপ ইনজেকশন ঘৃণা করি। সুতরাং, $ সময়সীমা এবং _.ডিফার এখনও অবধি আমাদের প্রিয়। এই পদ্ধতিগুলি সফলভাবে কৌণিককে পরবর্তী অ্যানিমেশন লুপ পর্যন্ত অপেক্ষা করতে বলে, যা গ্যারান্টি দেবে যে বর্তমান সুযোগটি। প্রয়োগ শেষ হয়ে গেছে।


2
এটি কি $ টাইমআউট (...) ব্যবহারের সাথে তুলনীয়? আমি পরবর্তী ইভেন্ট চক্রটি স্থগিত করতে বেশ কয়েকটি ক্ষেত্রে $ টাইমআউট ব্যবহার করেছি এবং এটি ভাল কাজ করছে বলে মনে হচ্ছে - know টাইমআউট ব্যবহার না করার কারণ আছে কিনা তা কি কেউ জানেন?
ট্রেভর

9
আপনি যদি ইতিমধ্যে ব্যবহার করছেন তবে এটি সত্যিই ব্যবহার করা উচিত underscore.js। এই সমাধানটি কেবলমাত্র তার deferকার্যকারিতাটি ব্যবহার করার জন্য পুরো আন্ডারস্কোর লাইব্রেরি আমদানি করার মতো নয় । আমি $timeoutসমাধানটি বেশি পছন্দ করি কারণ প্রত্যেকেরই ইতিমধ্যে $timeoutঅন্যান্য লাইব্রেরিতে কোনও নির্ভরতা ছাড়াই কৌণিক মাধ্যমে অ্যাক্সেস রয়েছে ।
টেনিসেন্ট

10
সত্য ... তবে আপনি যদি আন্ডারস্কোর বা লোড্যাশ ব্যবহার না করেন ... আপনি যা করছেন তা পুনর্বিবেচনা করা দরকার। এই দুটি libs সেই কোডটির চেহারা পরিবর্তন করেছে।
ফ্রস্টি

2
আমাদের রেস্ট্যাঙ্গুলারের নির্ভরতা হিসাবে লড্যাশ রয়েছে (আমরা শীঘ্রই এনজি-রুটের পক্ষে রেস্টাঙ্গুলারকে সরিয়ে ফেলব)। আমি মনে করি এটি একটি ভাল উত্তর তবে লোকেরা আন্ডারস্কোর / লোড্যাশ ব্যবহার করতে চায় তা ধরে নেওয়া দুর্দান্ত নয়। সমস্ত উপায়ে এই লিবিগুলি ঠিক আছে ... আপনি যদি তাদের যথেষ্ট পরিমাণে ব্যবহার করেন ... আজকাল আমি ES5 পদ্ধতি ব্যবহার করি যা আমি আন্ডারস্কোর অন্তর্ভুক্ত করার কারণে 98% কারণটি মুছে ফেলে ।
ব্র্যাডগ্রিনস

2
আপনি ঠিকই বলেছেন @ এসজিটিপুকি। $ টাইমআউটটি ব্যবহার করার বিকল্পটি অন্তর্ভুক্ত করার জন্য আমি উত্তরটি পরিবর্তন করেছি। $ সময়সীমা এবং _.ডিফার উভয়ই পরবর্তী অ্যানিমেশন লুপ পর্যন্ত অপেক্ষা করবে, যা বর্তমান সুযোগটি নিশ্চিত করবে। প্রয়োগ শেষ হয়ে গেছে। আমাকে সৎ রাখার জন্য, এবং উত্তরটি এখানে আপডেট করার জন্য আপনাকে ধন্যবাদ।
হিমশীতল

267

এখানে বেশিরভাগ উত্তরে ভাল পরামর্শ রয়েছে তবে বিভ্রান্তির কারণও হতে পারে। কেবলমাত্র ব্যবহার $timeoutহয় না শ্রেষ্ঠ বা অধিকার সমাধান। এছাড়াও, আপনি যদি পারফরম্যান্স বা স্কেলাবিলিটি দ্বারা উদ্বিগ্ন হন তা নিশ্চিত হয়ে নিন।

বিষয়গুলি আপনার জানা উচিত

  • $$phase কাঠামোর ব্যক্তিগত এবং এটির জন্য ভাল কারণ রয়েছে।

  • $timeout(callback)অপেক্ষা করবে যতক্ষণ না বর্তমান ডাইজেস্ট চক্র (যদি থাকে) সম্পন্ন করা হয়, তারপর কলব্যাক, তারপর একটি পূর্ণ শেষে চালানো চালানো $apply

  • $timeout(callback, delay, false)একই কাজ করবে (কলব্যাক কার্যকর করার আগে delayচ্ছিক বিলম্বের সাথে), তবে এমন কোনও $apply(তৃতীয় যুক্তি) ফায়ার করবে না যা আপনি নিজের কৌণিক মডেল ($ সুযোগ) পরিবর্তন না করে পারফরম্যান্স সংরক্ষণ করে।

  • $scope.$apply(callback)অন্যান্য জিনিসের মধ্যেও অনুরোধ জানায়, $rootScope.$digestযার অর্থ এটি কোনও বিচ্ছিন্ন সুযোগের মধ্যে থাকা সত্ত্বেও এটি প্রয়োগের মূল ক্ষেত্র এবং এর সমস্ত বাচ্চাদের পুনরায় বিতরণ করবে।

  • $scope.$digest()এটির মডেলটি কেবল দর্শনে সিঙ্ক করবে তবে এর পিতামাতাদের স্কোপ হজম করবে না, যা বিচ্ছিন্ন সুযোগের (বেশিরভাগ নির্দেশিকা থেকে) আপনার HTML এর কোনও বিচ্ছিন্ন অংশে কাজ করার সময় প্রচুর পারফরম্যান্স বাঁচাতে পারে। gest ডাইজেস্ট কলব্যাক নেয় না: আপনি কোডটি কার্যকর করেন, তারপরে হজম করুন।

  • $scope.$evalAsync(callback)Angularjs 1.2 এর সাথে প্রবর্তিত হয়েছে এবং সম্ভবত আপনার বেশিরভাগ সমস্যার সমাধান করবে। এটি সম্পর্কে আরও জানার জন্য দয়া করে শেষ অনুচ্ছেদটি দেখুন।

  • যদি আপনি এটি পান $digest already in progress error, তবে আপনার আর্কিটেকচারটি ভুল: হয় আপনার নিজের সুযোগ পুনর্নির্মাণের প্রয়োজন হয় না, বা আপনাকে তার দায়িত্বে থাকা উচিত নয় (নীচে দেখুন)।

আপনার কোডটি কীভাবে গঠন করবেন

যখন আপনি এই ত্রুটিটি পান, আপনি ইতিমধ্যে প্রগতিতে থাকা অবস্থায় আপনি আপনার সুযোগ হজম করার চেষ্টা করছেন: যেহেতু আপনি সেই মুহুর্তে আপনার সুযোগের অবস্থা জানেন না, তাই আপনি তার হজমের সাথে আচরণ করার দায়িত্বে নেই।

function editModel() {
  $scope.someVar = someVal;
  /* Do not apply your scope here since we don't know if that
     function is called synchronously from Angular or from an
     asynchronous code */
}

// Processed by Angular, for instance called by a ng-click directive
$scope.applyModelSynchronously = function() {
  // No need to digest
  editModel();
}

// Any kind of asynchronous code, for instance a server request
callServer(function() {
  /* That code is not watched nor digested by Angular, thus we
     can safely $apply it */
  $scope.$apply(editModel);
});

এবং যদি আপনি জানেন যে আপনি কী করছেন এবং একটি বিচ্ছিন্ন ছোট নির্দেশে কাজ করছেন যখন একটি বড় কৌনিক অ্যাপ্লিকেশনটির অংশ, আপনি পারফরম্যান্সগুলি সংরক্ষণ করার জন্য আবেদন করতে "ডায়জেস্টের পরিবর্তে" ডোজ করতে পছন্দ করতে পারেন।

অ্যাঙ্গুলারজ 1.2 এর পরে আপডেট Update

একটি নতুন, শক্তিশালী পদ্ধতি যে কোনও $ সুযোগে যুক্ত করা হয়েছে: $evalAsync । মূলত, এটি ঘটতে থাকলে এটি বর্তমান ডাইজেস্ট চক্রের মধ্যে তার কলব্যাক কার্যকর করবে, অন্যথায় একটি নতুন ডাইজেস্ট চক্র কলব্যাকটি কার্যকর করা শুরু করবে।

এটি এখনও ততটা ভাল নয় $scope.$digestযদি আপনি সত্যিই জানেন যে আপনার কেবলমাত্র আপনার এইচটিএমএলের একটি বিচ্ছিন্ন অংশটি সিঙ্ক্রোনাইজ $applyকরতে হবে (যেহেতু কোনওটিই প্রগতিতে না থাকলে একটি নতুন ট্রিগার করা হবে) তবে আপনি কোনও কার্য সম্পাদন করার সময় এটিই সেরা সমাধান is যা আপনি এটি জানতে পারবেন না সিঙ্ক্রোনিকভাবে কার্যকর করা হবে কি না , উদাহরণস্বরূপ সম্ভাব্য ক্যাশেড সংস্থান আনার পরে: কখনও কখনও এটির জন্য একটি সার্ভারে একটি অ্যাসিঙ্ক কল প্রয়োজন হয়, অন্যথায় স্থানীয়ভাবে সংস্থানটি সংশ্লেষিতভাবে নেওয়া হবে।

এই ক্ষেত্রে এবং অন্য যে সমস্ত জায়গায় আপনার ছিল !$scope.$$phase, ব্যবহার নিশ্চিত হন$scope.$evalAsync( callback )


4
$timeoutপাস করার সমালোচনা করা হয়। আপনি এড়াতে আরও কারণ দিতে পারেন $timeout?
mlhDev

88

এই প্রক্রিয়াটি DRY রাখতে সামান্য সহায়ক সহায়ক পদ্ধতি:

function safeApply(scope, fn) {
    (scope.$$phase || scope.$root.$$phase) ? fn() : scope.$apply(fn);
}

6
আপনার নিরাপদ অ্যাপ্লিকেশন আমাকে বুঝতে সাহায্য করেছে যে অন্য কিছুর চেয়ে অনেক বেশি কী চলছে। পোস্ট করার জন্য ধন্যবাদ।
জেসন মোর

4
আমি একই কাজটি করতে যাচ্ছিলাম, তবে এটি করার অর্থ এই নয় যে আমরা fn () এ যে পরিবর্তনগুলি করেছি তা $ ডাইজেস্ট দ্বারা দেখা যাবে না? সুযোগটি ধরে নিয়ে ফাংশনটি বিলম্ব করা আরও ভাল হবে না? $$ ফেজ === 'gest ডাইজেস্ট'?
স্পেন্সার অ্যালজার

আমি সম্মত হই, কখনও কখনও $ প্রয়োগ () ডাইজেস্টকে ট্রিগার করতে ব্যবহৃত হয়, কেবল নিজেই fn কল করে ... এর ফলে কোনও সমস্যার সৃষ্টি হবে না?
সিএমসিডিগ্রাগনকাই

1
আমার মনে হচ্ছে এমন scope.$apply(fn);হওয়া উচিত scope.$apply(fn());কারণ fn () ফাংশনটি কার্যকর করবে এবং fn না। আমি যেখানে ভুল করছি আমাকে দয়া করে সহায়তা করুন
madhu131313

1
@ জেনআউট $ এপ্লিকেশন কলটি ফাংশন সহ বিভিন্ন ধরণের যুক্তি সমর্থন করে। যদি কোনও ফাংশন পাস হয় তবে এটি ফাংশনটি মূল্যায়ন করে।
বক্সমাইন

33

আমার যেমন তৃতীয় পক্ষের স্ক্রিপ্টগুলির মতো কোডমিরার এবং উদাহরণস্বরূপ ক্র্পানোও একই সমস্যা ছিল এবং এমনকি এখানে বর্ণিত নিরাপদ প্রয়োগ পদ্ধতিগুলিও আমার জন্য ত্রুটিটি সমাধান করে নি।

তবে কী এটি সমাধান করেছে তা হ'ল $ টাইমআউট পরিষেবা (এটি প্রথমে ইনজেক্ট করতে ভুলবেন না)।

সুতরাং, যেমন কিছু:

$timeout(function() {
  // run my code safely here
})

এবং যদি আপনার কোডের অভ্যন্তরে আপনি ব্যবহার করছেন

এই

সম্ভবত কারণ এটি কারখানার নির্দেশকের নিয়ন্ত্রণকারীর ভিতরে বা কেবল কোনও ধরণের বাধ্যবাধকতার প্রয়োজন হয়, তবে আপনি যেমন কিছু করতে চান:

.factory('myClass', [
  '$timeout',
  function($timeout) {

    var myClass = function() {};

    myClass.prototype.surprise = function() {
      // Do something suprising! :D
    };

    myClass.prototype.beAmazing = function() {
      // Here 'this' referes to the current instance of myClass

      $timeout(angular.bind(this, function() {
          // Run my code safely here and this is not undefined but
          // the same as outside of this anonymous function
          this.surprise();
       }));
    }

    return new myClass();

  }]
)

32

Http://docs.angularjs.org/error/$rootScope:inprog দেখুন

সমস্যাটি দেখা দেয় যখন আপনার কাছে কোনও কল আসে যখন $applyকখনও কখনও কৌণিক কোডের বাইরে অবিচ্ছিন্নভাবে চালিত হয় (কখন $ প্রয়োগ করা উচিত) ব্যবহার করা উচিত) এবং কখনও কখনও সিঙ্ক্রোনিকভাবে অ্যাংুলার কোডের ভিতরে (যা $digest already in progressত্রুটির কারণ হয় )।

এটি ঘটতে পারে, উদাহরণস্বরূপ, যখন আপনার কাছে এমন একটি গ্রন্থাগার রয়েছে যা অবিচ্ছিন্নভাবে কোনও সার্ভার থেকে আইটেমগুলি নিয়ে আসে এবং সেগুলি ক্যাশে করে। কোনও আইটেমটি প্রথমবারের জন্য অনুরোধ করা হলে এটি কোডটি কার্যকর করার ক্ষেত্রে অবরুদ্ধ না হওয়ার কারণে এটি অবিচ্ছিন্নভাবে পুনরুদ্ধার করা হবে। তবে দ্বিতীয় বার, আইটেমটি ইতিমধ্যে ক্যাশে রয়েছে যাতে এটি সিঙ্ক্রোনালি পুনরুদ্ধার করা যায়।

এই ত্রুটি প্রতিরোধের উপায়টি হল যে কোডটি কল করে $applyতা অবিচ্ছিন্নভাবে চালিত হয়েছে তা নিশ্চিত করা । $timeoutদেরিতে সেট করতে 0(যা পূর্বনির্ধারিত) এর সাথে একটি কোডের মধ্যে আপনার কোড চালিয়ে এটি করা যেতে পারে । তবে আপনার $timeoutকোডটির ভিতরে কল করা কল করার প্রয়োজনীয়তা সরিয়ে দেয় $apply, কারণ $ সময়সীমা $digestনিজে থেকে অন্য একটি চক্রকে ট্রিগার করবে , যার ফলে, সমস্ত প্রয়োজনীয় আপডেটিং ইত্যাদি করবে etc.

সমাধান

সংক্ষেপে, এটি করার পরিবর্তে:

... your controller code...

$http.get('some/url', function(data){
    $scope.$apply(function(){
        $scope.mydate = data.mydata;
    });
});

... more of your controller code...

এটা কর:

... your controller code...

$http.get('some/url', function(data){
    $timeout(function(){
        $scope.mydate = data.mydata;
    });
});

... more of your controller code...

কেবলমাত্র কল করুন $applyযখন আপনি কোডটি চালাচ্ছেন এটি সর্বদা কৌণিক কোডের বাইরে চালানো হবে (যেমন আপনার কলটি $ প্রয়োগ করা হবে এমন কলব্যাকের অভ্যন্তরে ঘটবে যা আপনার কৌণিক কোডের বাইরের কোড দ্বারা কল করা হয়)।

$timeoutওভার ব্যবহারের ক্ষেত্রে কেউ যদি কিছু প্রভাবশালী অসুবিধাগুলি সম্পর্কে অবগত $applyনা হয় তবে আমি দেখতে পাই না যে আপনি কেন সর্বদা $timeout(শূন্য বিলম্বের সাথে) পরিবর্তে ব্যবহার করতে পারেননি $apply, কারণ এটি প্রায় একই জিনিসটি করবে।


ধন্যবাদ, এটি আমার ক্ষেত্রে কাজ করেছে যেখানে আমি $applyনিজেকে কল করছি না তবুও ত্রুটি পাচ্ছি ।
এরিসক্রিস

5
মূল পার্থক্যটি হ'ল এটি $applyসিঙ্ক্রোনাস (এর কলব্যাকটি কার্যকর করা হয়, তারপরে কোডটি অনুসরণ করে) প্রয়োগ করা হয়) যখন $timeoutনা থাকে: বর্তমান কোড নিম্নলিখিত সময়সীমা কার্যকর করা হয়, তারপরে একটি নতুন স্ট্যাকটি তার কলব্যাক দিয়ে শুরু হয়, যেমন আপনি ব্যবহার করছেন setTimeout। যদি আপনি একই মডেলটিকে দু'বার আপডেট করে থাকেন তবে গ্রাফিক সমস্যা দেখা দিতে পারে: $timeoutআবার আপডেট করার আগে ভিউটি সতেজ হওয়ার জন্য অপেক্ষা করবে।
ফ্লোরিবোন

থ্যাঙ্কস প্রকৃতপক্ষে। কিছু ঘড়ির ক্রিয়াকলাপের ফলস্বরূপ আমার কাছে একটি পদ্ধতি বলা হয়েছিল এবং আমার বাহ্যিক ফিল্টারটি সম্পাদন শেষ হওয়ার আগেই ইউআই আপডেট করার চেষ্টা করছিলাম। এটি একটি out টাইমআউট ফাংশনের ভিতরে রেখে দেওয়া আমার পক্ষে কাজ করে।
djmarquette

28

আপনি যখন এই ত্রুটিটি পান, এটির মূলত অর্থ এটি ইতিমধ্যে আপনার ভিউ আপডেট করার প্রক্রিয়াধীন। $apply()আপনার নিয়ামকের মধ্যে আপনাকে কল করার দরকার নেই । যদি আপনার ভিউটি আপনার প্রত্যাশা মতো আপডেট না হয় এবং কল করার পরে আপনি এই ত্রুটিটি পেয়ে থাকেন তবে এর $apply()সম্ভবত সম্ভবত আপনি মডেলটি সঠিকভাবে আপডেট করছেন না। আপনি যদি কিছু সুনির্দিষ্ট পোস্ট করেন তবে আমরা মূল সমস্যাটি বের করতে পারি।


হেই, আমি পুরো দিনটি ব্যয় করে জানতে পেরেছিলাম যে AngularJS কেবল "ম্যাজিকালি" বাঁধাই দেখতে পারে না এবং মাঝে মাঝে $ প্রয়োগ () দিয়ে তাকে আমার ধাক্কা দেওয়া উচিত।
ওজেড

আসলে কি you're not updating the the model correctly? $scope.err_message = 'err message';সঠিক আপডেট না?
ওজেড

2
$apply()যখন আপনি কৌণিকের "বাইরের" মডেলটি আপডেট করেন (কেবল একটি জিকুয়েরি প্লাগইন থেকে) কেবল তখনই আপনাকে কল করতে হবে। ঠিক মতো দেখতে না পেয়ে ভিউয়ের ফাঁদে পড়ে যাওয়া সহজ, এবং তাই আপনি $apply()সর্বত্রই একটি গোছা ফেলে দেন, যারপরে ওপিতে দেখা ত্রুটিটি শেষ হয়। যখন আমি বলি যে you're not updating the the model correctlyআমি কেবলমাত্র সমস্ত ব্যবসায়ের যুক্তিটি সঠিকভাবে এমন কোনও কিছুকে পপুলেশন না করাতে চাই যা সুযোগের মধ্যে থাকতে পারে, যা প্রত্যাশাকে প্রত্যাশিতভাবে দেখায় না এমন দিকে পরিচালিত করে।
dnc253

@ dnc253 আমি সম্মত, এবং আমি উত্তরটি লিখেছি। আমি এখন কী জানি তা জানতে, আমি $ টাইমআউট (ফাংশন () {...}) ব্যবহার করব; এটি _.ডিফারের মতো একই কাজ করে। তারা উভয়ই পরবর্তী অ্যানিমেশন লুপে পিছিয়ে যায়।
হিমশীতল


11

আপনি evalAsync ব্যবহার করতে পারেন। হজম শেষ হওয়ার পরে এটি চলবে!

scope.evalAsync(function(scope){
    //use the scope...
});

10

প্রথমত, এটি এইভাবে ঠিক করবেন না

if ( ! $scope.$$phase) { 
  $scope.$apply(); 
}

এটি বোঝায় না কারণ $ পর্বটি $ ডাইজেস্ট চক্রের জন্য কেবল একটি বুলিয়ান পতাকা, তাই আপনার $ প্রয়োগ () কখনও কখনও চলবে না। এবং মনে রাখবেন এটি একটি খারাপ অভ্যাস।

পরিবর্তে, ব্যবহার করুন $timeout

    $timeout(function(){ 
  // Any code in here will automatically have an $scope.apply() run afterwards 
$scope.myvar = newValue; 
  // And it just works! 
});

আপনি যদি আন্ডারস্কোর বা লড্যাশ ব্যবহার করেন তবে আপনি ডিফার () ব্যবহার করতে পারেন:

_.defer(function(){ 
  $scope.$apply(); 
});

9

আপনি যদি এইভাবে ব্যবহার করেন তবে কখনও কখনও ত্রুটিগুলি পাবেন ( https://stackoverflow.com/a/12859093/801426 )।

এটা চেষ্টা কর:

if(! $rootScope.$root.$$phase) {
...

5
উভয়ই ব্যবহার করে!। সুযোগ। $$ পর্যায় এবং!। সুযোগ। $ মূল। $$ পর্ব (না! $ রুটস্কোপ। +1
asprotte

2
$rootScopeএবং anyScope.$rootএকই লোক $rootScope.$rootঅপ্রয়োজনীয়।
ফ্লোরিবন


5

ব্যবহার করার চেষ্টা করুন

$scope.applyAsync(function() {
    // your code
});

পরিবর্তে

if(!$scope.$$phase) {
  //$digest or $apply
}

$ প্রয়োগআসেন্সির সময়সূচী a পরবর্তী সময়ে ঘটতে প্রয়োগ করুন of এটি একাধিক অভিব্যক্তি সারিবদ্ধ করতে ব্যবহৃত হতে পারে যা একই ডাইজেস্টে মূল্যায়ন করা দরকার।

দ্রষ্টব্য: scope ডাইজেস্টের মধ্যে, scope প্রয়োগএসাইক () কেবলমাত্র তখনই প্রবাহিত হবে যদি বর্তমান স্কোপটি $ রুটস্কোপ হয়। এর অর্থ হ'ল আপনি যদি কোনও শিশু স্কোপকে $ ডাইজেস্ট কল করেন তবে এটি সুস্পষ্টভাবে $ প্রয়োগআসাইক () সারিটি ফ্লাশ করবে না।

Exmaple:

  $scope.$applyAsync(function () {
                if (!authService.authenticated) {
                    return;
                }

                if (vm.file !== null) {
                    loadService.setState(SignWizardStates.SIGN);
                } else {
                    loadService.setState(SignWizardStates.UPLOAD_FILE);
                }
            });

তথ্যসূত্র:

1. স্কোপ। $ প্রয়োগঅ্যাসেন্স () বনাম স্কোপ। Ang অ্যাভুলারএন্সিঙ্ক () এঙ্গুলারজেএস 1.3 এ

  1. AngularJs ডক্স

4

আমি আপনাকে ডাইজেস্ট চক্রটি ট্রিগার না করে একটি কাস্টম ইভেন্ট ব্যবহার করার পরামর্শ দেব।

আমি জানতে পেরেছি যে কাস্টম ইভেন্টগুলি সম্প্রচার করা এবং এই ইভেন্টগুলির জন্য শ্রোতাদের নিবন্ধিত করা আপনি ডাইজেস্ট চক্রের মধ্যে রয়েছেন বা না থাকাকালীন আপনি যে কোনও ক্রিয়াকলাপ ঘটতে চান তা ট্রিগার করার জন্য ভাল সমাধান।

একটি কাস্টম ইভেন্ট তৈরি করে আপনি আপনার কোডটির সাথে আরও দক্ষ হচ্ছেন কারণ আপনি কেবল কথিত ইভেন্টটির সদস্যতা প্রাপ্ত শ্রোতাদের ট্রিগার করছেন এবং সুযোগকে আবদ্ধ করলে সমস্ত ঘড়িটি আপনাকে সুযোগের সাথে সীমাবদ্ধ করে না $ প্রয়োগ করুন।

$scope.$on('customEventName', function (optionalCustomEventArguments) {
   //TODO: Respond to event
});


$scope.$broadcast('customEventName', optionalCustomEventArguments);

3

Yearofmoo আমাদের জন্য পুনরায় ব্যবহারযোগ্য - নিরাপদ প্রয়োগের ফাংশন তৈরিতে দুর্দান্ত কাজ করেছে:

https://github.com/yearofmoo/AngularJS-Scope.SafeApply

ব্যবহার:

//use by itself
$scope.$safeApply();

//tell it which scope to update
$scope.$safeApply($scope);
$scope.$safeApply($anotherScope);

//pass in an update function that gets called when the digest is going on...
$scope.$safeApply(function() {

});

//pass in both a scope and a function
$scope.$safeApply($anotherScope,function() {

});

//call it on the rootScope
$rootScope.$safeApply();
$rootScope.$safeApply($rootScope);
$rootScope.$safeApply($scope);
$rootScope.$safeApply($scope, fn);
$rootScope.$safeApply(fn);

2

আমি জানি যে ফাংশনটি চলবে সেই জায়গাগুলির $evalপরিবর্তে কল করে $applyআমি এই সমস্যাটি সমাধান করতে সক্ষম হয়েছি $digest

ডক্স অনুসারে , $applyমূলত এটি করে:

function $apply(expr) {
  try {
    return $eval(expr);
  } catch (e) {
    $exceptionHandler(e);
  } finally {
    $root.$digest();
  }
}

আমার ক্ষেত্রে, ng-clickএকটি স্কোপের মধ্যে একটি ভেরিয়েবল পরিবর্তন করে এবং সেই ভেরিয়েবলের উপর নজর রাখার ফলে অন্যান্য ভেরিয়েবল পরিবর্তন হয় $applied। এই শেষ পদক্ষেপটি "ইতিমধ্যে প্রক্রিয়ায় ডাইজেস্ট" ত্রুটির কারণ ঘটায়।

$applyসঙ্গে প্রতিস্থাপন$eval ঘড়ি অভিব্যক্তি ভিতরে সুযোগ ভেরিয়েবল যেমন প্রত্যাশিত আপডেট করুন।

অতএব, এটি উপস্থিত হয় যে অ্যাঙ্গুলারের মধ্যে অন্য কোনও পরিবর্তনের কারণে যদি ডাইজেস্ট যেভাবে চলতে থাকে তবে $eval'আইএনজি আপনাকে যা করতে হবে তা হ'ল।



1

বুঝুন যে কৌণিক কাগজপত্র চেক কল $$phaseএকটি অ্যান্টি-প্যাটার্ন , আমি পাওয়ার চেষ্টা $timeoutএবং _.deferকাজ।

সময়সীমা এবং স্থগিত পদ্ধতিগুলি FOUT এর{{myVar}} মতো ডোমে আনপারসড সামগ্রীর একটি ফ্ল্যাশ তৈরি করে । আমার জন্য এটি গ্রহণযোগ্য ছিল না। এটি আমাকে অনেক কিছু ছাড়াই ছেড়ে দেয় যা কৌতুকপূর্ণভাবে বলা যায় যে কিছু হ্যাক, এবং এর উপযুক্ত বিকল্প নেই।

প্রতিবার কাজ করা একমাত্র জিনিস:

if(scope.$$phase !== '$digest'){ scope.$digest() }

আমি এই পদ্ধতির বিপদ বা কেন এটি মন্তব্য এবং কৌণিক দলের লোকেরা হ্যাক হিসাবে বর্ণনা করেছি তা বুঝতে পারি না। কমান্ডটি সুনির্দিষ্ট এবং পড়া সহজ বলে মনে হচ্ছে:

"হজম করুন না যদি না কেউ ইতিমধ্যে ঘটছে"

কফিস্ক্রিপ্টে এটি আরও সুন্দর:

scope.$digest() unless scope.$$phase is '$digest'

এ নিয়ে সমস্যা কী? এমন কোনও বিকল্প আছে যা একটি ফল তৈরি করবে না? $ নিরাপদ অ্যাপ্লিকেশনটি দেখতে দুর্দান্ত দেখায় তবে $$phaseপরিদর্শন পদ্ধতিটিও ব্যবহার করে ।


1
আমি এই প্রশ্নের একটি জ্ঞাত প্রতিক্রিয়া দেখতে চাই!
বেন হুইলার

এটি একটি হ্যাক কারণ এর অর্থ হল আপনি প্রসঙ্গটি মিস করেছেন বা কোডটি এই বিন্দুটি বুঝতে পারেন না: হয় আপনি কৌণিক ডাইজেস্ট চক্রের মধ্যে রয়েছেন এবং আপনার এটির দরকার নেই, বা আপনার অ্যাসিঙ্ক্রোনালিভাবে এর বাইরে আছেন এবং তারপরে আপনার এটির প্রয়োজন। আপনি যদি
কোডটির

1

এটি আমার ব্যবহার পরিষেবা:

angular.module('myApp', []).service('Utils', function Utils($timeout) {
    var Super = this;

    this.doWhenReady = function(scope, callback, args) {
        if(!scope.$$phase) {
            if (args instanceof Array)
                callback.apply(scope, Array.prototype.slice.call(args))
            else
                callback();
        }
        else {
            $timeout(function() {
                Super.doWhenReady(scope, callback, args);
            }, 250);
        }
    };
});

এবং এটি এর ব্যবহারের উদাহরণ example

angular.module('myApp').controller('MyCtrl', function ($scope, Utils) {
    $scope.foo = function() {
        // some code here . . .
    };

    Utils.doWhenReady($scope, $scope.foo);

    $scope.fooWithParams = function(p1, p2) {
        // some code here . . .
    };

    Utils.doWhenReady($scope, $scope.fooWithParams, ['value1', 'value2']);
};

1

আমি এই পদ্ধতিটি ব্যবহার করছি এবং এটি পুরোপুরি সূক্ষ্মভাবে কাজ করবে বলে মনে হচ্ছে। এটি কেবল চক্রটি শেষ হওয়ার এবং তারপরে ট্রিগার হওয়া সময়ের জন্য অপেক্ষা করে apply()apply(<your scope>)আপনি যে কোনও জায়গা থেকে ফাংশনটি কেবল কল করুন ।

function apply(scope) {
  if (!scope.$$phase && !scope.$root.$$phase) {
    scope.$apply();
    console.log("Scope Apply Done !!");
  } 
  else {
    console.log("Scheduling Apply after 200ms digest cycle already in progress");
    setTimeout(function() {
        apply(scope)
    }, 200);
  }
}

1

আমি যখন ডিবাগারটি অক্ষম করি তখন ত্রুটিটি আর হয় না। আমার ক্ষেত্রে , এটি ডিবাগার কোড কার্যকর করা বন্ধ করে দেওয়ার কারণে হয়েছিল।


0

উপরের উত্তরের মতই তবে এটি আমার জন্য বিশ্বস্ততার সাথে কাজ করেছে ... একটি পরিষেবা যুক্ত করুন:

    //sometimes you need to refresh scope, use this to prevent conflict
    this.applyAsNeeded = function (scope) {
        if (!scope.$$phase) {
            scope.$apply();
        }
    };


0

ইস্যুটি মূলত তখনই আসবে যখন, আমরা ডাইজেস্ট চক্রটি চালনার জন্য কৌনিককে অনুরোধ করছি যদিও এটি প্রক্রিয়াধীন রয়েছে যা বোঝার ক্ষেত্রে কৌণিকের জন্য সমস্যা তৈরি করছে। কনসোলে ফলাফল ব্যতিক্রম।
১. স্কোপ কল করার কোনও ধারণা নেই। টাইমআউট ফাংশনের অভ্যন্তরে (প্রয়োগ করুন () কারণ অভ্যন্তরীণভাবে এটি একই কাজ করে।
২. কোডটি ভ্যানিলা জাভাস্ক্রিপ্ট ফাংশনের সাথে যায় কারণ এর নেটিভ নয় কৌণিক সংজ্ঞায়িত অর্থাৎ সেটটাইমআউট
৩. এটি করার জন্য আপনি

যদি (! সুযোগ।। পর্ব) {
স্কোপ ব্যবহার করতে পারেন তবে evalAsync (ফাংশন () {

}); }


0
        let $timeoutPromise = null;
        $timeout.cancel($timeoutPromise);
        $timeoutPromise = $timeout(() => {
            $scope.$digest();
        }, 0, false);

এই ত্রুটিটি এড়াতে এবং এড়াতে avoid প্রয়োগ এড়াতে ভাল সমাধান এখানে

যদি আপনি বাহ্যিক ইভেন্টের ভিত্তিতে কল করে থাকেন তবে আপনি এটি ডিবাউন (0) এর সাথে একত্রিত করতে পারেন। উপরে আমরা ব্যবহার করছি এমন 'ডিবাউন' এবং কোডের পুরো উদাহরণ

.factory('debounce', [
    '$timeout',
    function ($timeout) {

        return function (func, wait, apply) {
            // apply default is true for $timeout
            if (apply !== false) {
                apply = true;
            }

            var promise;
            return function () {
                var cntx = this,
                    args = arguments;
                $timeout.cancel(promise);
                promise = $timeout(function () {
                    return func.apply(cntx, args);
                }, wait, apply);
                return promise;
            };
        };
    }
])

এবং কোড নিজেই কিছু ইভেন্ট শোনার জন্য এবং কল করতে আপনাকে কেবলমাত্র স্কোপ-ডাইজেস্টকে কল করুন

        let $timeoutPromise = null;
        let $update = debounce(function () {
            $timeout.cancel($timeoutPromise);
            $timeoutPromise = $timeout(() => {
                $scope.$digest();
            }, 0, false);
        }, 0, false);

        let $unwatchModelChanges = $scope.$root.$on('updatePropertiesInspector', function () {
            $update();
        });


        $scope.$on('$destroy', () => {
            $timeout.cancel($update);
            $timeout.cancel($timeoutPromise);
            $unwatchModelChanges();
        });

-3

এটি খুঁজে পেয়েছে : https://coderwall.com/p/ngisma যেখানে নাথন ওয়াকার (পৃষ্ঠার নীচের অংশে) ফানক 'নিরাপদ অ্যাপ্লিকেশন', কোড তৈরি করতে $ রুটস্কোপের একটি সাজসজ্জার পরামর্শ দেয়:

yourAwesomeModule.config([
  '$provide', function($provide) {
    return $provide.decorator('$rootScope', [
      '$delegate', function($delegate) {
        $delegate.safeApply = function(fn) {
          var phase = $delegate.$$phase;
          if (phase === "$apply" || phase === "$digest") {
            if (fn && typeof fn === 'function') {
              fn();
            }
          } else {
            $delegate.$apply(fn);
          }
        };
        return $delegate;
      }
    ]);
  }
]);

-7

এটি আপনার সমস্যার সমাধান করবে:

if(!$scope.$$phase) {
  //TODO
}

(! $ সুযোগ। $$ পর্ব) $ সুযোগ। $ প্রয়োগ () প্রয়োগ করবেন না, এটির অর্থ আপনার $ সুযোগ। $ প্রয়োগ () কল স্ট্যাকের পর্যায়ে বেশি নয়।
MGot90
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.