(! $ সুযোগ। $$ পর্ব) $ সুযোগ। $ প্রয়োগ () একটি বিরোধী-প্যাটার্ন কেন ব্যবহার করছে?


92

কখনও কখনও $scope.$applyআমার কোডটি ব্যবহার করা দরকার এবং কখনও কখনও এটি "ডাইজেস্ট ইতিমধ্যে প্রগতিতে" ত্রুটি ছুড়ে দেয়। সুতরাং আমি এর আশেপাশে একটি উপায় সন্ধান করতে শুরু করেছি এবং এই প্রশ্নটি পেয়েছি: AngularJS: ত্রুটি প্রতিরোধ করুন already স্কোপ $ কল করার সময় ইতিমধ্যে প্রগতিতে ডাইজেস্ট $ প্রয়োগ করুন () । তবে মন্তব্যে (এবং কৌনিক উইকিতে) আপনি পড়তে পারেন:

(! $ সুযোগ। $$ পর্ব) $ সুযোগ। $ প্রয়োগ () প্রয়োগ করবেন না, এটির অর্থ আপনার $ সুযোগ $ $ প্রয়োগ () কল স্ট্যাকের পর্যাপ্ত পরিমাণে বেশি নয়।

সুতরাং এখন আমার দুটি প্রশ্ন আছে:

  1. কেন এটি ঠিক একটি বিরোধী নিদর্শন?
  2. আমি কীভাবে নিরাপদে $ সুযোগ।। প্রয়োগ করতে পারি?

"ডাইজেস্ট ইতিমধ্যে প্রগতিতে" রোধ করতে অন্য একটি "সমাধান" ত্রুটিটি $ টাইমআউটটি ব্যবহার করছে বলে মনে হচ্ছে:

$timeout(function() {
  //...
});

এটাই কি পথ? এটা কি নিরাপদ? সুতরাং আসল প্রশ্নটি এখানে: আমি কীভাবে "ইতিমধ্যে প্রক্রিয়াধীন ডাইজেস্ট" ত্রুটিটিকে সম্পূর্ণভাবে দূর করতে পারি ?

পিএস: আমি কেবল $ স্কোপ using ব্যবহার করছি non অ-কৌণিক কলস ব্যাকগুলিতে প্রয়োগ করুন যা সিঙ্ক্রোনাস নয়। (যতদূর আমি জানি এগুলি এমন পরিস্থিতিতে রয়েছে যেখানে আপনার অবশ্যই ব্যবহার করা উচিত $ সুযোগ $ আপনি যদি নিজের পরিবর্তনগুলি প্রয়োগ করতে চান তবে প্রয়োগ করুন)


আমার অভিজ্ঞতা থেকে আপনার সর্বদা জানা উচিত, আপনি যদি scopeকৌনিক থেকে বা কৌনিকের বাইরে থেকে চালিত হন। সুতরাং এটি অনুসারে আপনি সর্বদা জানেন, যদি আপনার কল করার দরকার হয় scope.$applyবা না। এবং যদি আপনি উভয় কৌনিক / অ-কৌণিক scopeম্যানিপুলেশন জন্য একই কোড ব্যবহার করছেন, আপনি এটি ভুল করছেন, এটি সর্বদা পৃথক করা উচিত ... সুতরাং আপনি যদি এমন কোনও ক্ষেত্রে যাচাই করতে চান তবে scope.$$phaseআপনার কোডটি নয় একটি সঠিক উপায়ে ডিজাইন করা হয়েছে এবং এটি করার জন্য সর্বদা একটি উপায় রয়েছে 'সঠিক উপায়ে'
ডুডেক

4
আমি এটি কেবল অ-কৌণিক কলব্যাকগুলিতে ব্যবহার করছি (!) এ কারণেই আমি বিভ্রান্ত
ডোমিনিক গলটারম্যান

4
যদি এটি অ-কৌণিক হয়, তবে এটি digest already in progressত্রুটি ছুঁড়ে ফেলবে না
ডুডেক 12'14

4
আমি যা ভেবেছিলাম. জিনিসটি হ'ল: এটি সর্বদা ত্রুটি ছুঁড়ে না। একবারে একবারে। আমার সন্দেহ হ'ল প্রয়োগটি চ্যান্সের সাথে অন্য ডাইজেস্টের সাথে সংঘর্ষ হয়। এটা কি সম্ভব?
ডোমিনিক গলটারম্যান

উত্তর:


113

আরও কিছু খননের পরে আমি প্রশ্নটি সমাধান করতে সক্ষম হয়েছি এটি ব্যবহার করা সর্বদা নিরাপদ কিনা $scope.$apply। সংক্ষিপ্ত উত্তর হল হ্যাঁ.

দীর্ঘ উত্তর:

আপনার ব্রাউজার জাভাস্ক্রিপ্ট কীভাবে কার্যকর করে, এর ফলে এটি সম্ভব নয় যে দুটি ডাইজেস্ট কল সুযোগের সাথে সংঘর্ষ হয়

আমরা যে জাভাস্ক্রিপ্ট কোডটি লিখি তা সব একসাথে চলবে না, পরিবর্তে এটি ঘুরিয়ে কার্যকর করে। এর প্রতিটি পালা শেষ থেকে শেষ পর্যন্ত নিরবচ্ছিন্নভাবে চলে এবং যখন কোনও পালা চলমান থাকে তখন আমাদের ব্রাউজারে আর কিছুই হয় না। ( http://jimhoskins.com/2012/12/17/angularjs-and-apply.html থেকে )

সুতরাং "ইতিমধ্যে ডাইজেস্ট প্রগতিতে" ত্রুটিটি কেবলমাত্র একটি পরিস্থিতিতেই ঘটতে পারে: যখন $ প্রয়োগ অন্যের মধ্যে জারি করা হয় $ প্রয়োগ করুন, যেমন:

$scope.apply(function() {
  // some code...
  $scope.apply(function() { ... });
});

এই পরিস্থিতি পারেন না উঠা যদি আমরা $ scope.apply একটি বিশুদ্ধ অ angularjs কলব্যাক মধ্যে মত কলব্যাক ব্যবহার করেন, উদাহরণস্বরূপ setTimeout। সুতরাং নীচের কোডটি 100% বুলেটপ্রুফ এবং এটি করার কোনও দরকার নেইif (!$scope.$$phase) $scope.$apply()

setTimeout(function () {
    $scope.$apply(function () {
        $scope.message = "Timeout called!";
    });
}, 2000);

এমনকি এটি নিরাপদ:

$scope.$apply(function () {
    setTimeout(function () {
        $scope.$apply(function () {
            $scope.message = "Timeout called!";
        });
    }, 2000);
});

কী নিরাপদ নয় (কারণ $ টাইমআউট - সমস্ত কৌণিক সাহায্যকারীদের মতো - ইতিমধ্যে $scope.$applyআপনাকে কল করেছে):

$timeout(function () {
    $scope.$apply(function () {
        $scope.message = "Timeout called!";
    });
}, 2000);

এটিও কেন ব্যাখ্যার if (!$scope.$$phase) $scope.$apply()বিরোধী নিদর্শন তা ব্যাখ্যা করে। আপনি যদি $scope.$applyসঠিক উপায়ে ব্যবহার করেন তবে আপনার কেবল এটির দরকার নেই : setTimeoutউদাহরণস্বরূপ খাঁটি জেএস কলব্যাকে ।

আরও বিশদ ব্যাখ্যার জন্য http://jimhoskins.com/2012/12/17/angularjs-and-apply.html পড়ুন ।


আমি একটি উদাহরণ পেয়েছি যেখানে আমি একটি পরিষেবা তৈরি করি $document.bind('keydown', function(e) { $rootScope.$apply(function() { // a passed through function from the controller gets executed here }); });আমি জানি না কেন আমাকে এখানে $ ডকুমেন্ট.বাইন্ড ব্যবহার করতে হবে, কারণ আমি কেন have ডকুমেন্ট.বাইন্ড ব্যবহার করতে হবে
বেটি সেন্ট

কারণ $ দস্তাবেজটি কেবল ব্রাউজারের উইন্ডো ডকুমেন্ট অবজেক্টের জন্য "একটি jQuery বা jqLite মোড়ক"। এবং নিম্নলিখিত হিসাবে প্রয়োগ করা হয়েছে: function $DocumentProvider(){ this.$get = ['$window', function(window){ return jqLite(window.document); }]; }সেখানে কোনও প্রয়োগ নেই।
ডোমিনিক গোলটারম্যান

11
$timeoutশব্দার্থগত অর্থ বিলম্বের পরে কোড চলমান। এটি করা কার্যকরীভাবে নিরাপদ জিনিস হতে পারে তবে এটি একটি হ্যাক। ব্যবহারের একটি নিরাপদ উপায় থাকতে হবে $ আপনি যখন $digestচক্রের অগ্রগতি চলছে বা আপনি ইতিমধ্যে একটি ভিতরে রয়েছেন কিনা তা জানতে অক্ষম হলে প্রয়োগ করুন $apply
জন স্ট্রিকলার 15

4
এর খারাপ হওয়ার অন্য কারণ: এটি অভ্যন্তরীণ ভেরিয়েবল ($$ ফেজ) ব্যবহার করে যা জনসাধারণের API এর অংশ নয় এবং এগুলি কৌণিকের নতুন সংস্করণে পরিবর্তিত হতে পারে এবং এইভাবে আপনার কোডটি ভেঙে দেয়। সিঙ্ক্রোনাস ইভেন্ট ট্রিগার সহ আপনার সমস্যাটি আকর্ষণীয় হলেও
ডোমিনিক গোলটারম্যান

4
নতুন পদ্ধতির মধ্যে হ'ল $ স্কোপ $ ব্যবহার করা $ evalAsync () যা সম্ভব হলে ডাইজেস্ট চক্রে বা পরবর্তী চক্রে নিরাপদে সম্পাদন করে। পড়ুন bennadel.com/blog/...
jaymjarri

16

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

আপনার ব্যবহার করা উচিত

 $scope.$evalAsync();

যেহেতু এটি কৌণিক ^ 1.4 এ পছন্দসই পদ্ধতি এবং অ্যাপ্লিকেশন স্তরটির জন্য একটি API হিসাবে বিশেষত উদ্ভাসিত।


9

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

প্রথমটি

if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') {
    $scope.$apply();
}

যদি উপরের শর্তটি সত্য হয়, তবে আপনি আপনার $ সুযোগ $ প্রয়োগ করতে পারেন এবং অন্যটি প্রয়োগ করুন এবং না

দ্বিতীয় সমাধানটি হ'ল সময়-সমাপ্তি

$timeout(function() {
  //...
})

এটি অপরটিকে হস্তান্তরিত হতে দেবে না ti সময়সীমা শেষ হওয়ার পরে এটি কার্যকর হয়।


4
নিম্নমানের প্রশ্নটি এখানে বিশেষভাবে জিজ্ঞাসা করছে যে আপনি এখানে যে জিনিসটি বর্ণনা করছেন তা কেন করবেন না, এটি অন্য কোনও উপায়ে হ্যাক করার জন্য নয়। কখন ব্যবহার করবেন তার জন্য @ গৌল দ্বারা দুর্দান্ত উত্তর দেখুন $scope.$apply();
PureSpider

প্রশ্নের উত্তর না দিলেও: $timeoutকী! এটি কাজ করে এবং পরে আমি দেখতে পেলাম যে এটিও প্রস্তাবিত।
হিমেল নাগ রানা

আমি জানি যে এটি 2 বছর পরে এই সম্পর্কে মন্তব্য যোগ করতে বেশ দেরি হয়েছে, তবে
out

9

scope.$applyএকটি $digestচক্রকে ট্রিগার করে যা দ্বিমুখী ডেটা বাঁধাইয়ের মৌলিক

একটি $digestচক্র পরীক্ষা করে যা বস্তুর জন্য মডেলগুলি (সুনির্দিষ্ট হতে হবে $watch) $scopeতাদের মানগুলি পরিবর্তিত হয়েছে কিনা তা নির্ধারণের জন্য সংযুক্ত এবং এটি যদি কোনও পরিবর্তন সনাক্ত করে তবে ভিউটি আপডেট করার জন্য এটি প্রয়োজনীয় পদক্ষেপ গ্রহণ করে।

এখন আপনি যখন $scope.$apply"তত্ক্ষণে চলছে" ত্রুটির মুখোমুখি হন তখন একটি স্পষ্টতই স্পষ্ট হয় যে একটি $ ডাইজেস্ট চলছে তবে কী তা ট্রিগার করেছিল?

উত্তর -> প্রতিটি $httpকল, সমস্ত এনজি-ক্লিক, পুনরাবৃত্তি, প্রদর্শন, লুকান ইত্যাদি একটি $digestচক্রকে ট্রিগার করে এবং দ্য ওয়ার্ল্ড পার্ট আইটি $ স্কোরের সমস্ত অংশ।

অর্থ্যাৎ আপনার পৃষ্ঠায় 4 টি নিয়ামক বা নির্দেশিকা রয়েছে এ, বি, সি, ডি

যদি $scopeসেগুলির প্রত্যেকটিতে আপনার 4 টি সম্পত্তি থাকে তবে আপনার পৃষ্ঠায় মোট 16 $ স্কোপ বৈশিষ্ট্য রয়েছে।

আপনি যদি $scope.$applyকন্ট্রোলার ডি ট্রিগার করেন তবে একটি $digestচক্র সমস্ত 16 টি মান পরীক্ষা করবে !!! প্লাস সমস্ত $ রুটস্কোপ বৈশিষ্ট্য।

উত্তর -> তবে শিশু এবং একই সুযোগে এটি $scope.$digestট্রিগার $digestকরে যাতে এটি কেবল 4 টি বৈশিষ্ট্য পরীক্ষা করে। সুতরাং আপনি যদি নিশ্চিত হন যে ডি-এর পরিবর্তনগুলি এ, বি, সি প্রভাবিত করবে না তবে $scope.$digesটি ব্যবহার করবেন না $scope.$apply

সুতরাং কোনও এনজি-ক্লিক বা এনজি-শো / লুকান $digestব্যবহারকারীর কোনও ইভেন্ট বরখাস্ত না করা সত্ত্বেও 100+ এরও বেশি সংখ্যায় একটি চক্র চালু করতে পারে !


4
হ্যাঁ আমি দুর্ভাগ্যক্রমে প্রকল্পের মধ্যে এই দেরী বুঝতে পেরেছি। আমি যদি প্রথম থেকেই এটি জানতাম তবে কৌণিক ব্যবহার করা হত না। সমস্ত স্ট্যান্ডার্ড নির্দেশাবলী একটি $ সুযোগ। Fire প্রয়োগ করে, যার পরিবর্তে কলগুলি $ রুটস্কোপ $ ডাইজেস্ট, যা সমস্ত স্কোপগুলিতে নোংরা চেক করে। আপনি যদি আমাকে জিজ্ঞাসা করেন তবে দরিদ্র ডিজাইনের সিদ্ধান্ত। কী স্কোপগুলি নোংরা চেক করা উচিত তা আমার নিয়ন্ত্রণে রাখা উচিত, কারণ আমি জানি যে এই স্কোপের সাথে ডেটা কীভাবে লিঙ্ক করা আছে!
মুনস্টম

0

ব্যবহার করুন $timeout, এটি প্রস্তাবিত উপায়।

আমার পরিস্থিতিটি হ'ল যে আমি ওয়েবসকেট থেকে প্রাপ্ত ডেটার ভিত্তিতে পৃষ্ঠায় আইটেমগুলি পরিবর্তন করতে পারি। এবং যেহেতু এটি কৌণিকের বাইরে, $ সময়সীমা ছাড়াই, একমাত্র মডেলটি পরিবর্তন হবে তবে দৃশ্যটি নয়। কারণ কৌণিক জানেন না যে ডেটা টুকরা পরিবর্তন করা হয়েছে। $timeoutমূলত অ্যাঙ্গুলারকে round ডাইজেস্টের পরবর্তী রাউন্ডে পরিবর্তন আনতে বলছে।

আমি নিম্নলিখিতগুলিও চেষ্টা করেছিলাম এবং এটি কার্যকর হয়। আমার কাছে পার্থক্যটি হল $ সময়সীমা আরও পরিষ্কার।

setTimeout(function(){
    $scope.$apply(function(){
        // changes
    });
},0)

আপনার সকেট কোডটি $ প্রয়োগে মোড়ানো বেশ ক্লিনার (অনেকটা অ্যাজেএক্স কোডে অ্যাংুলারের মতো, যেমন $http)। অন্যথায় আপনাকে সমস্ত জায়গাতে এই কোডটি পুনরাবৃত্তি করতে হবে।
টিমরুফলস

এটি অবশ্যই প্রস্তাবিত নয়। এছাড়াও, $ সুযোগ। পর্যায়ে থাকলে আপনি মাঝে মাঝে এটি করতে একটি ত্রুটি পাবেন। পরিবর্তে, আপনি $ সুযোগ ব্যবহার করা উচিত $ evalAsync ();
ফ্ল্যাওয়ারস্কেপ

$scope.$applyআপনি ব্যবহার করছেন setTimeoutবা নেই$timeout
কুণাল

-1

আমি খুব দুর্দান্ত সমাধান পেয়েছি:

.factory('safeApply', [function($rootScope) {
    return function($scope, fn) {
        var phase = $scope.$root.$$phase;
        if (phase == '$apply' || phase == '$digest') {
            if (fn) {
                $scope.$eval(fn);
            }
        } else {
            if (fn) {
                $scope.$apply(fn);
            } else {
                $scope.$apply();
            }
        }
    }
}])

আপনার যেখানে প্রয়োজন সেখানে ইনজেক্ট করুন:

.controller('MyCtrl', ['$scope', 'safeApply',
    function($scope, safeApply) {
        safeApply($scope); // no function passed in
        safeApply($scope, function() { // passing a function in
        });
    }
])
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.