এটি আপনার প্রশ্নের সম্পূর্ণ উত্তর হতে যাচ্ছে না, তবে আপনি যখন $q
পরিষেবাতে নথিপত্র পড়ার চেষ্টা করবেন তখন আশা করি এটি আপনাকে এবং অন্যদের সহায়তা করবে । এটি বুঝতে আমার কিছুটা সময় লেগেছে।
আসুন এক মুহুর্তের জন্য অ্যাঙ্গুলারজেএস আলাদা করে রাখি এবং কেবল ফেসবুক এপিআই কলগুলি বিবেচনা করি। উভয় এপিআই কল কলব্যাককে কলবিকে অবহিত করার জন্য কল্পনা করে যখন ফেসবুকের কাছ থেকে প্রতিক্রিয়া পাওয়া যায়:
facebook.FB.api('/' + item, function (result) {
if (result.error) {
// handle error
} else {
// handle success
}
});
// program continues while request is pending
...
এটি জাভাস্ক্রিপ্ট এবং অন্যান্য ভাষায় অ্যাসিনক্রোনাস অপারেশন পরিচালনা করার জন্য একটি আদর্শ প্যাটার্ন।
এই প্যাটার্নের সাথে একটি বড় সমস্যা দেখা দেয় যখন আপনাকে অ্যাসিক্রোনাস অপারেশনগুলির ক্রম সম্পাদন করতে হবে, যেখানে প্রতিটি ক্রমিক ক্রিয়া পূর্ববর্তী ক্রিয়াকলাপের ফলাফলের উপর নির্ভর করে। এই কোডটি এটাই করছে:
FB.login(function(response) {
if (response.authResponse) {
FB.api('/me', success);
} else {
fail('User cancelled login or did not fully authorize.');
}
});
প্রথমে এটি লগ ইন করার চেষ্টা করে এবং তারপরেই লগইন সফল হয়েছিল তা যাচাইয়ের পরে এটি গ্রাফ এপিআইতে অনুরোধ করে।
এমনকি এই ক্ষেত্রে, যা কেবল দুটি ক্রিয়াকলাপকে এক সাথে শৃঙ্খলিত করছে, জিনিসগুলি অগোছালো হতে শুরু করে। পদ্ধতিটি askFacebookForAuthentication
ব্যর্থতা এবং সাফল্যের জন্য একটি কলব্যাক গ্রহণ করে, তবে FB.login
সফল হয় কিন্তু FB.api
ব্যর্থ হলে কী ঘটে ? পদ্ধতির success
ফলাফল নির্বিশেষে এই পদ্ধতিটি সর্বদা কলব্যাকের ডাক দেয় FB.api
।
এখন কল্পনা করুন যে আপনি তিন বা ততোধিক অ্যাসিনক্রোনাস অপারেশনের একটি শক্তিশালী অনুক্রম কোড করার চেষ্টা করছেন, যাতে প্রতিটি পদক্ষেপে ত্রুটিগুলি সঠিকভাবে পরিচালনা করে এবং অন্য কারও কাছে বা কয়েক সপ্তাহ পরেও আপনার কাছে সুস্পষ্ট হয়ে উঠতে পারে। সম্ভব, তবে কেবল সেই কলব্যাকগুলিকে বাসা বাঁধতে এবং পথে ত্রুটির ট্র্যাক হারিয়ে ফেলাই খুব সহজ।
এখন, আসুন আমরা একটি মুহুর্তের জন্য ফেসবুক এপিআইকে আলাদা করে রাখি এবং কেবলমাত্র $q
পরিষেবা দ্বারা প্রয়োগ করা হিসাবে কৌনিক প্রতিশ্রুতি API বিবেচনা করি । এই পরিষেবাদির দ্বারা প্রয়োগ করা প্যাটার্ন হ'ল অ্যাসিক্রোনাস প্রোগ্রামিংকে সাধারণ বিবৃতিগুলির একটি রৈখিক সিরিজের অনুরূপ কিছুতে ফিরিয়ে আনার চেষ্টা, উপায়টির কোনও ধাপে ত্রুটি 'নিক্ষেপ' করার ক্ষমতা এবং শেষে এটি হ্যান্ডেল করার মতো ক্ষমতা পরিচিত try/catch
ব্লক
এই স্বীকৃত উদাহরণ বিবেচনা করুন। বলুন আমাদের দুটি ফাংশন রয়েছে, যেখানে দ্বিতীয় ফাংশনটি প্রথমটির ফলাফল গ্রাস করে:
var firstFn = function(param) {
// do something with param
return 'firstResult';
};
var secondFn = function(param) {
// do something with param
return 'secondResult';
};
secondFn(firstFn());
এখন কল্পনা করুন যে ফার্স্টফেন এবং সেকেন্ডফ্যান উভয়ই সম্পূর্ণ হতে দীর্ঘ সময় নেয়, তাই আমরা এই ক্রমটি অ্যাসিঙ্ক্রোনালি প্রক্রিয়া করতে চাই। প্রথমে আমরা একটি নতুন deferred
অবজেক্ট তৈরি করি , যা ক্রিয়াকলাপের প্রতিনিধিত্ব করে:
var deferred = $q.defer();
var promise = deferred.promise;
promise
সম্পত্তি ব্যবস্থাপনার পরিণামস্বরূপ ফলাফলের প্রতিনিধিত্ব করে। আপনি যদি কোনও প্রতিশ্রুতি তৈরির সাথে সাথে লগ করেন তবে দেখতে পাবেন যে এটি কেবল একটি খালি অবজেক্ট ( {}
)। এখনও দেখার মতো কিছুই নেই, ডানদিকে চলুন।
এখনও অবধি আমাদের প্রতিশ্রুতি কেবল চেইনের প্রারম্ভিক পয়েন্ট উপস্থাপন করে। এখন আমাদের দুটি অপারেশন যুক্ত করুন:
promise = promise.then(firstFn).then(secondFn);
then
পদ্ধতি চেইন একটি পদক্ষেপ যোগ করা হয়েছে এবং তারপর নতুন প্রতিশ্রুতি বর্ধিত চেন পরিণামস্বরূপ ফলাফলের প্রতিনিধিত্বমূলক ফেরৎ। আপনি নিজের পছন্দমতো পদক্ষেপ যুক্ত করতে পারেন।
এখনও অবধি, আমরা আমাদের ক্রিয়াকলাপগুলি নির্ধারণ করেছি, তবে বাস্তবে কিছুই ঘটেনি। আপনি deferred.resolve
চেইনের প্রথম আসল ধাপে যেতে চান এমন প্রাথমিক মান নির্দিষ্ট করে কল করে আপনি জিনিসগুলি শুরু করবেন :
deferred.resolve('initial value');
এবং তারপরে ... এখনও কিছুই হয় না। মডেল পরিবর্তনগুলি যথাযথভাবে পর্যবেক্ষণ করা হয়েছে তা নিশ্চিত করার জন্য, পরের বার $apply
ডাকা না হওয়া পর্যন্ত কৌণিক আসলে চেইনের প্রথম পদক্ষেপটি কল করে না :
deferred.resolve('initial value');
$rootScope.$apply();
// or
$rootScope.$apply(function() {
deferred.resolve('initial value');
});
সুতরাং ত্রুটি পরিচালনা সম্পর্কে কি? এখনও অবধি আমরা কেবল চেইনের প্রতিটি ধাপে একটি সাফল্য হ্যান্ডলার নির্দিষ্ট করেছি । then
একটি ত্রুটি হ্যান্ডলারকে secondচ্ছিক দ্বিতীয় আর্গুমেন্ট হিসাবেও গ্রহণ করে। এখানে আরও একটি প্রতিশ্রুতি শৃঙ্খলার দীর্ঘ উদাহরণ, এ বার ত্রুটি পরিচালনার সাথে:
var firstFn = function(param) {
// do something with param
if (param == 'bad value') {
return $q.reject('invalid value');
} else {
return 'firstResult';
}
};
var secondFn = function(param) {
// do something with param
if (param == 'bad value') {
return $q.reject('invalid value');
} else {
return 'secondResult';
}
};
var thirdFn = function(param) {
// do something with param
return 'thirdResult';
};
var errorFn = function(message) {
// handle error
};
var deferred = $q.defer();
var promise = deferred.promise.then(firstFn).then(secondFn).then(thirdFn, errorFn);
আপনি যেমন এই উদাহরণটিতে দেখতে পারেন, চেইনের প্রতিটি হ্যান্ডলারের পরবর্তী সাফল্য হ্যান্ডলারের পরিবর্তে ট্র্যাফিকটিকে পরবর্তী ত্রুটি হ্যান্ডলারের দিকে সরানোর সুযোগ রয়েছে । বেশিরভাগ ক্ষেত্রে চেইনের শেষে আপনার একক ত্রুটি হ্যান্ডলার থাকতে পারে, তবে পুনরুদ্ধারের চেষ্টা করে এমন মধ্যবর্তী ত্রুটি হ্যান্ডলারগুলি আপনার কাছে থাকতে পারে।
আপনার উদাহরণগুলিতে (এবং আপনার প্রশ্নসমূহ) দ্রুত ফিরে আসার জন্য, আমি কেবলই বলব যে তারা মডেল পরিবর্তনগুলি পর্যবেক্ষণের পদ্ধতিতে অ্যাঙ্গুলারের পদ্ধতিতে ফেসবুকের কলব্যাক ভিত্তিক এপিআই মানিয়ে নেওয়ার জন্য দুটি ভিন্ন উপায়ে উপস্থাপন করে। প্রথম উদাহরণটি এপিআই কলকে একটি প্রতিশ্রুতিতে আবৃত করে, যা কোনও স্কোপে যুক্ত করা যেতে পারে এবং অ্যাংুলারের টেম্প্লেটিং সিস্টেম দ্বারা বোঝা যায়। দ্বিতীয়টি সরাসরি সুযোগের উপর কলব্যাকের ফলাফল নির্ধারণের আরও নিষ্ঠুর বল প্রয়োগ করে এবং তার পরে $scope.$digest()
বহিরাগত উত্স থেকে পরিবর্তন সম্পর্কে কৌণিককে সচেতন করার আহ্বান জানায় ।
দুটি উদাহরণ সরাসরি তুলনাযোগ্য নয়, কারণ প্রথমটিতে লগইন পদক্ষেপটি অনুপস্থিত। যাইহোক, এটি পৃথক পরিষেবাগুলিতে এই জাতীয় বাহ্যিক এপিআইয়ের সাথে ইন্টারঅ্যাকশনগুলি আবদ্ধ করা এবং প্রতিশ্রুতি হিসাবে নিয়ামকদের কাছে ফলাফল সরবরাহ করা সাধারণত বাঞ্ছনীয়। এইভাবে আপনি আপনার কন্ট্রোলারগুলিকে বাহ্যিক উদ্বেগ থেকে আলাদা রাখতে পারেন এবং মক পরিষেবাদি দিয়ে আরও সহজেই তাদের পরীক্ষা করতে পারেন।