স্পষ্ট প্রতিশ্রুতি নির্মাণ প্রতিরোধী কী এবং আমি কীভাবে এড়াতে পারি?


516

আমি কোড লিখছিলাম যা এমন কিছু করে যা দেখে মনে হয়:

function getStuffDone(param) {           | function getStuffDone(param) {
    var d = Q.defer(); /* or $q.defer */ |     return new Promise(function(resolve, reject) {
    // or = new $.Deferred() etc.        |     // using a promise constructor
    myPromiseFn(param+1)                 |         myPromiseFn(param+1)
    .then(function(val) { /* or .done */ |         .then(function(val) {
        d.resolve(val);                  |             resolve(val);
    }).catch(function(err) { /* .fail */ |         }).catch(function(err) {
        d.reject(err);                   |             reject(err);
    });                                  |         });
    return d.promise; /* or promise() */ |     });
}                                        | }

কেউ আমাকে বলেছিল এটিকে যথাক্রমে " মুলতুবি অ্যান্টিপ্যাটার্ন " বা " Promiseকনস্ট্রাক্টর অ্যান্টিপ্যাটার্ন " বলা হয়, এই কোডটি কী খারাপ এবং কেন এটিকে অ্যান্টিপ্যাটার্ন বলা হয় ?


আমি কী নিশ্চিত করতে পারি যে এটি হ'ল (ডানদিকে, বাম নয়, প্রসঙ্গে) getStuffDoneফাংশন র‌্যাপারটি সরিয়ে কেবল প্রতিশ্রুতি আক্ষরিক ব্যবহার করতে হবে?
ডেমবিনস্কি

1
বা র‍্যাপারে অ্যান্টিপ্যাটার্নে catchব্লক রয়েছে getStuffDone?
ডেম্বিনস্কি

1
কমপক্ষে নেটিভ Promiseউদাহরণের জন্য আপনার কাছে .thenএবং .catchহ্যান্ডলারের জন্য অপ্রয়োজনীয় ফাংশন র‌্যাপারগুলিও রয়েছে (যেমন এটি কেবল হতে পারে .then(resolve).catch(reject))) বিরোধী নিদর্শনগুলির একটি নিখুঁত ঝড়।
নোহ

6
@ নোহফ্রেইটাস যে কোডটি সেভাবে লেখা হয়েছে যুক্তিযুক্ত উদ্দেশ্যে for আমি এই প্রশ্ন এবং উত্তরটি লিখেছি যাতে এই সমস্যাটি দেখে এমন লোকেরা যাতে দেখতে অনেক কোড পড়ে এই সমস্যাটি চালায় help :)
বেনজামিন গ্রুইনবাউম

কীভাবে কেবল সুস্পষ্ট প্রতিশ্রুতি নির্মাণই নয়, বৈশ্বিক পরিবর্তনশীল ব্যবহারও কীভাবে বাদ দিতে হয় তার জন্য এছাড়াও stackoverflow.com/questions/57661537/… দেখুন ।
ডেভিড স্পেক্টর ২:01

উত্তর:


357

ডেফার্ড antipattern (বর্তমানে স্পষ্ট নির্মাণাধীন antipattern) দ্বারা উদ্ভাবিত Esailija একটি সাধারণ antipattern যারা নতুন প্রতিশ্রুতি করতে হয়, আমি নিজেকে যখন আমি প্রথম ব্যবহৃত প্রতিশ্রুতি করেছি। উপরের কোডটি নিয়ে সমস্যাটি হ'ল চেইনের প্রতিশ্রুতি দেওয়া সত্যটি কাজে লাগাতে ব্যর্থ।

প্রতিশ্রুতিগুলি চেইন .thenকরতে পারে এবং আপনি সরাসরি প্রতিশ্রুতি দিতে পারেন। আপনার কোডটি এ getStuffDoneহিসাবে আবারও লেখা যেতে পারে:

function getStuffDone(param){
    return myPromiseFn(param+1); // much nicer, right?
}

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

আপনি যখন প্রতিশ্রুতিতে কোনও এপিআই রূপান্তর করছেন কেবল তখনই আপনার পিছিয়ে থাকা অবজেক্টগুলি ব্যবহার করা উচিত এবং স্বয়ংক্রিয়ভাবে এটি করতে পারবেন না করতে পারেন, বা আপনি যখন এগ্রিগেশন ফাংশনগুলি সহজেই প্রকাশ করেছেন এটি লিখছেন।

এসাইলিজা উদ্ধৃত:

এটি সর্বাধিক সাধারণ অ্যান্টি-প্যাটার্ন। আপনি সত্যিকার অর্থে প্রতিশ্রুতিগুলি বুঝতে না পারলে এবং এগুলিকে গৌরবময় ইভেন্ট প্রেরক বা কলব্যাক ইউটিলিটি হিসাবে ভাবেন না এমন সময়ে এগুলি পড়া সহজ। আসুন পুনরুদ্ধার করা যাক: প্রতিশ্রুতিগুলি অ্যাসিক্রোনাস কোড তৈরির বিষয়ে রয়েছে সমকালীন কোডের হারিয়ে যাওয়া বেশিরভাগ বৈশিষ্ট্য যেমন ফ্ল্যাট ইন্ডেন্টেশন এবং একটি ব্যতিক্রম চ্যানেল retain


@ বেনজামিন গ্রুয়েনবাউম: আমি এর জন্য আমার পিছিয়ে থাকা ব্যবহারের বিষয়ে আমি আত্মবিশ্বাসী, সুতরাং নতুন প্রশ্নের দরকার নেই। আমি কেবল ভেবেছিলাম এটি আপনার ব্যবহারের থেকে অনুপস্থিত ছিল এমন একটি ব্যবহারের কেস। আমি যা করছি তা আরও একত্রিত হওয়ার বিপরীতে মনে হচ্ছে, তাই না?
মিলভেন্ভস

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

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

@ মেলভেনস আমি অনুমান করি যে অতিরিক্ত মুলতুবি বিরোধী প্যাটার্নটি এটি আসলে যা করে তার জন্য আরও নির্ভুল হবে। ব্লুবার্ড এপিআইকে .defer()নতুন (এবং নিরাপদে নিক্ষেপ) প্রতিশ্রুতিবদ্ধ নির্মাণকারীর নিকট অবহিত করেছে, এটি প্রতিশ্রুতিগুলি নির্মাণের ধারণাটিকে (
কোনওভাবেই ছাড়েনি

1
আপনাকে ধন্যবাদ @ রোমের -1888 আপনার রেফারেন্স আমাকে শেষ পর্যন্ত আমার সমস্যাটি কী তা আবিষ্কার করতে সহায়তা করেছিল। দেখে মনে হচ্ছে যে আমি এটি উপলব্ধি না করে নেস্টেড (অবারিত) প্রতিশ্রুতি তৈরি করছি।
ঘুরুর

134

এতে দোষ কী?

কিন্তু প্যাটার্ন কাজ করে!

ভাগ্যবান তুমি. দুর্ভাগ্যক্রমে, সম্ভবত এটি হবেনা, আপনি সম্ভবত কিছু প্রান্তের কেসটি ভুলে গেছেন। আমি যে ঘটনাগুলি দেখেছি তার অর্ধেকেরও বেশিটিতে, ত্রুটি পরিচালকের যত্ন নিতে লেখক ভুলে গিয়েছেন:

return new Promise(function(resolve) {
    getOtherPromise().then(function(result) {
        resolve(result.property.example);
    });
})

যদি অন্য প্রতিশ্রুতি প্রত্যাখাত হয়, তবে নতুন প্রতিশ্রুতি প্রচার করার পরিবর্তে এটি নজরে না আসবে (যেখানে এটি পরিচালনা করা হবে) - এবং নতুন প্রতিশ্রুতি চিরতরে মুলতুবি থেকে যায়, যা ফাঁস হতে পারে।

আপনার কলব্যাক কোডটি ত্রুটির কারণ ঘটায় একই জিনিস ঘটে - যেমন কখন resultনা থাকেproperty এবং ব্যতিক্রম ছুঁড়ে দেওয়া হয়। এটি নিরবচ্ছিন্ন হয়ে যাবে এবং নতুন প্রতিশ্রুতিটি অমীমাংসিত ছেড়ে দেবে।

বিপরীতে, ব্যবহার .then()এই দুটি পরিস্থিতিতেই স্বয়ংক্রিয়ভাবে যত্ন নেয় এবং কোনও ত্রুটি ঘটলে নতুন প্রতিশ্রুতি প্রত্যাখ্যান করে:

 return getOtherPromise().then(function(result) {
     return result.property.example;
 })

মুলতুবি অ্যান্টিপ্যাটার্ন কেবল জটিলই নয়, ত্রুটি- প্রবণও । .then()শিকল দেওয়ার জন্য ব্যবহার করা অনেক বেশি নিরাপদ।

তবে আমি সব কিছু পরিচালনা করেছি!

সত্যি? ভাল. যাইহোক, এটি বেশ বিস্তারিত এবং কৌতুকপূর্ণ হবে, বিশেষত যদি আপনি কোনও প্রতিশ্রুতি পাঠাগার ব্যবহার করেন যা বাতিলকরণ বা বার্তা প্রেরণের মতো অন্যান্য বৈশিষ্ট্যগুলিকে সমর্থন করে। অথবা ভবিষ্যতে এটি হতে পারে, বা আপনি একটি ভাল এর বিরুদ্ধে আপনার লাইব্রেরি অদলবদল করতে চান? আপনি তার জন্য আপনার কোডটি আবার লিখতে চাইবেন না।

গ্রন্থাগারগুলির পদ্ধতিগুলি ( then) কেবল স্থানীয়ভাবে সমস্ত বৈশিষ্ট্যকে সমর্থন করে না, তাদের স্থানে কিছু নির্দিষ্ট অপ্টিমাইজেশনও থাকতে পারে। এগুলি ব্যবহার করা সম্ভবত আপনার কোডটি দ্রুততর করবে বা কমপক্ষে গ্রন্থাগারের ভবিষ্যতে সংশোধন করে অনুকূলিত হওয়ার অনুমতি দেবে।

আমি কীভাবে এড়াতে পারি?

সুতরাং আপনি যখনই নিজেকে ম্যানুয়ালি তৈরি করতে দেখেন Promiseবা Deferredইতিমধ্যে বিদ্যমান প্রতিশ্রুতি জড়িত থাকে, প্রথমে লাইব্রেরি এপিআই পরীক্ষা করে দেখুন । বিলম্বিত antipattern প্রায়ই যারা প্রতিশ্রুতি দেখতে দ্বারা প্রয়োগ করা হয় [শুধুমাত্র] একটি পর্যবেক্ষক প্যাটার্ন হিসাবে - কিন্তু প্রতিশ্রুতি হয় আরো callbacks চেয়ে তারা অনুমিত হয় composable যাবে। প্রতিশ্রুতিবদ্ধ পদ্ধতিতে প্রতিশ্রুতি রচনার জন্য প্রতিটি শালীন গ্রন্থাগারের প্রচুর সহজেই ব্যবহারযোগ্য ফাংশন রয়েছে, আপনি যে সমস্ত নিম্ন-স্তরের জিনিসগুলি মোকাবেলা করতে চান না তার যত্ন নিয়ে।

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


কোনও ফাংশন ব্যতীত অন্যান্য উদাহরণ রয়েছে setTimeout, যেখানে কন্সট্রাক্টর ব্যবহার করা যেতে পারে তবে "প্রতিশ্রুতি কনস্ট্রাক্টর অ্যানিটপ্যাটার্ন" হিসাবে বিবেচিত হয় না?
অতিথি 271314

1
@ অতিথি 271314: অ্যাসিঙ্ক্রোনাস যা কিছু প্রতিশ্রুতি দেয় না। যদিও প্রায়শই পর্যাপ্ত আপনি গ্রন্থাগারগুলির নিবেদিত প্রতিশ্রুতিবদ্ধ সাহায্যকারীদের সাথে আরও ভাল ফলাফল পাবেন। এবং সর্বদা সর্বনিম্ন স্তরে প্রচার করার বিষয়টি নিশ্চিত করুন, সুতরাং এটি " সহ একটি ফাংশনsetTimeout " নয়, " নিজেই ফাংশনsetTimeout "।
বার্গি

"এবং সর্বদা সর্বনিম্ন স্তরে প্রচার করার বিষয়টি নিশ্চিত করুন, সুতরাং এটি" সহ একটি ফাংশন setTimeout"নয়, তবে" ফাংশনটি setTimeoutনিজেই "" উভয়ের মধ্যে পার্থক্যটির বর্ণনা দিতে পারে, লিঙ্ক দিতে পারে?
অতিথি 271314

@ guest271314 একটি ফাংশন যে শুধু একটি কল অন্তর্ভুক্ত setTimeoutথেকে পরিষ্কারভাবে ভিন্ন ফাংশন setTimeoutনিজেই , তাই না?
বার্গি

4
আমি মনে করি এখানে গুরুত্বপূর্ণ পাঠগুলির মধ্যে একটি, যা এখনও অবধি পরিষ্কারভাবে বলা হয়নি, তা হল কোনও প্রতিশ্রুতি এবং এর শৃঙ্খলিত 'তারপরে' একটি অ্যাসিনক্রোনাস অপারেশনকে উপস্থাপন করে: প্রাথমিক ক্রিয়াকলাপ প্রতিশ্রুতিবদ্ধ কনস্ট্রাক্টরের মধ্যে রয়েছে এবং শেষ অবধি ' তারপরে 'ফাংশন। সুতরাং আপনার যদি একটি সিঙ্ক অপারেশন হয় এবং তারপরে একটি অ্যাসিঞ্চ অপারেশন হয়, তবে সিঙ্কের জিনিসগুলি প্রতিশ্রুতিতে রাখুন। আপনার যদি একটি সিঙ্কের পরে একটি অ্যাসিঙ্ক অপারেশন থাকে তবে সিঙ্কের জিনিসগুলি 'তখন' তে রাখুন। প্রথম ক্ষেত্রে, আসল প্রতিশ্রুতি ফিরিয়ে দিন। দ্বিতীয় ক্ষেত্রে, প্রতিশ্রুতি / তারপরে চেইনটি ফিরিয়ে দিন (এটিও একটি প্রতিশ্রুতি)।
ডেভিড স্পেক্টর
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.