প্রতিশ্রুতিতে একাধিক ক্যাচ পরিচালনা করা


125

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

সুতরাং উদাহরণস্বরূপ আমার মত একটি এক্সপ্রেস অ্যাপ্লিকেশন মধ্যে একটি প্রতিশ্রুতি শৃঙ্খল আছে:

repository.Query(getAccountByIdQuery)
        .catch(function(error){
            res.status(404).send({ error: "No account found with this Id" });
        })
        .then(convertDocumentToModel)
        .then(verifyOldPassword)
        .catch(function(error) {
            res.status(406).send({ OldPassword: error });
        })
        .then(changePassword)
        .then(function(){
            res.status(200).send();
        })
        .catch(function(error){
            console.log(error);
            res.status(500).send({ error: "Unable to change password" });
        });

সুতরাং আমি যে আচরণটি করছি তা হ'ল:

  • আইডির মাধ্যমে অ্যাকাউন্ট পেতে যায়
  • যদি এই সময়ে কোনও প্রত্যাখ্যান হয় তবে বোমা ফাটিয়ে একটি ত্রুটি ফিরিয়ে দিন
  • যদি কোনও ত্রুটি না থাকে তবে দস্তাবেজটিকে কোনও মডেলে ফিরিয়ে আনুন
  • ডাটাবেস নথির সাহায্যে পাসওয়ার্ড যাচাই করুন
  • যদি পাসওয়ার্ডগুলি মেলে না তবে বোমা ফাটিয়ে একটি ভিন্ন ত্রুটি ফিরে আসবে
  • কোনও ত্রুটি না থাকলে পাসওয়ার্ডগুলি পরিবর্তন করুন
  • তারপরে সাফল্য ফিরিয়ে দিন
  • অন্য কিছু যদি ভুল হয়ে থাকে তবে একটি 500 ফিরিয়ে দিন

সুতরাং বর্তমানে ক্যাচগুলি শৃঙ্খলা বন্ধ করে দেবে বলে মনে হয় না, এবং এটি উপলব্ধি করে তোলে, তাই আমি ভাবছি যে আমার জন্য যদি কোনও উপায় ত্রুটির উপর ভিত্তি করে কোনও নির্দিষ্ট বিন্দুতে শৃঙ্খলা বন্ধ করতে বাধ্য করা হয়, বা আরও ভাল উপায় আছে কিনা? এর কাঠামোগত শাখা আচরণের কিছু ফর্ম পেতে, যেমন আছে তেমন একটি ঘটনা if X do Y else Z

যেকোনো সাহায্যই অসাধারণ.


আপনি হয় পুনর্বিবেচনা বা প্রথম দিকে ফিরে আসতে পারেন?
পিটার 21

উত্তর:


126

এই আচরণটি হুবহু একটি সিনক্রোনাস থ্রোকের মতো:

try{
    throw new Error();
} catch(e){
    // handle
} 
// this code will run, since you recovered from the error!

.catchত্রুটি থেকে পুনরুদ্ধার করতে সক্ষম হতে - এটি পয়েন্টের অর্ধেক । রাষ্ট্রটি এখনও একটি ত্রুটি হিসাবে সংকেত দিতে পুনর্বিবেচনা করা বাঞ্ছনীয় হতে পারে:

try{
    throw new Error();
} catch(e){
    // handle
    throw e; // or a wrapper over e so we know it wasn't handled
} 
// this code will not run

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

যোগ করা সুবিধাটি হ'ল আপনার ব্যবসায়ের যুক্তিটি অনুরোধ / প্রতিক্রিয়া চক্র সম্পর্কে মোটেই সচেতন হতে হবে না। ক্লায়েন্টটি কোন HTTP স্থিতি এবং ত্রুটিটি পেয়েছে এবং পরে আপনার অ্যাপ্লিকেশন বাড়ার সাথে সাথে আপনি ক্লায়েন্টকে যা পাঠিয়েছেন তা থেকে ব্যবসায়ের যুক্তি (কীভাবে আপনার ডিবিকে জিজ্ঞাসা করতে হবে এবং কীভাবে আপনার ডেটা প্রক্রিয়াকরণ করতে হবে) আলাদা করতে চাইলে সিদ্ধান্ত নেওয়া কোয়েরির দায়িত্ব নয় decide (কি HTTP স্থিতি কোড, কোন পাঠ্য এবং কি প্রতিক্রিয়া)।

আমি এখানে আপনার কোডটি লিখব।

প্রথমে, আমি .Queryএকটি নিক্ষেপ NoSuchAccountErrorকরব, আমি এটি সাবক্লাস করব Promise.OperationalErrorযা থেকে ব্লুবার্ড ইতিমধ্যে সরবরাহ করেছে। আপনি যদি নিশ্চিত না হন তবে কীভাবে একটি ত্রুটি সাবক্লাস করবেন তা আমাকে জানান।

আমি এটির জন্য অতিরিক্ত সাবক্লাস AuthenticationErrorকরব এবং তারপরে এমন কিছু করব:

function changePassword(queryDataEtc){ 
    return repository.Query(getAccountByIdQuery)
                     .then(convertDocumentToModel)
                     .then(verifyOldPassword)
                     .then(changePassword);
}

আপনি দেখতে পাচ্ছেন - এটি খুব পরিষ্কার এবং আপনি প্রক্রিয়াতে কী ঘটে যায় তার নির্দেশিকা ম্যানুয়ালটির মতো পাঠ্যটি পড়তে পারেন। এটি অনুরোধ / প্রতিক্রিয়া থেকে পৃথক করা হয়।

এখন, আমি এটির মতো রুট হ্যান্ডলার থেকে কল করব:

 changePassword(params)
 .catch(NoSuchAccountError, function(e){
     res.status(404).send({ error: "No account found with this Id" });
 }).catch(AuthenticationError, function(e){
     res.status(406).send({ OldPassword: error });
 }).error(function(e){ // catches any remaining operational errors
     res.status(500).send({ error: "Unable to change password" });
 }).catch(function(e){
     res.status(500).send({ error: "Unknown internal server error" });
 });

এইভাবে, যুক্তিগুলি সমস্ত এক জায়গায় এবং ক্লায়েন্টকে কীভাবে ত্রুটিগুলি পরিচালনা করতে হবে তার সিদ্ধান্ত সবই এক জায়গায় এবং তারা প্রত্যেকে বিশৃঙ্খলা সৃষ্টি করে না।


11
আপনি যুক্ত করতে চাইতে পারেন যে .catch(someSpecificError)কিছু নির্দিষ্ট ত্রুটির জন্য মধ্যবর্তী হ্যান্ডেলারের কারণ হ'ল যদি আপনি একটি নির্দিষ্ট ধরণের ত্রুটি ধরতে চান (তবে এটি নির্দোষ নয়), এটি মোকাবেলা করুন এবং এরপরে প্রবাহটি অবিরত রাখুন। উদাহরণস্বরূপ, আমার কাছে কিছু স্টার্টআপ কোড রয়েছে যা করার মতো ক্রম রয়েছে। প্রথমটি হ'ল ডিস্ক থেকে কনফিগারেশন ফাইলটি পড়া, তবে যদি সেই কনফিগারেশন ফাইলটি ভুল করে থাকে তবে এটি একটি ওকে ত্রুটি (প্রোগ্রামটি ডিফল্টে তৈরি করেছে) তাই আমি সেই নির্দিষ্ট ত্রুটিটি পরিচালনা করতে পারি এবং বাকী প্রবাহটি চালিয়ে যেতে পারি। পরে অবধি ছেড়ে না রাখা আরও ভাল পরিষ্কার হতে পারে।
jفر00

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

1
ব্লুবার্ড ব্যবহার না করা হলে কী হবে? সরল এস 6 প্রতিশ্রুতিতে কেবল একটি স্ট্রিং ত্রুটি বার্তা থাকে যা ধরতে পাস হয়।
ক্লকস্মিত

3
ES6 সহ @ ক্লকস্মিত প্রতিশ্রুতি দিয়েছিলেন যে আপনি instanceofনিজেই সমস্ত কিছু ধরতে এবং নিজেই চেকস আটকে রেখেছেন।
বেনজামিন গ্রুইনবাউম

1
সাবক্লাসিং ত্রুটিযুক্ত বস্তুর জন্য রেফারেন্সের জন্য যারা খুঁজছেন তাদের জন্য নীলবर्डজস / ডকস / অ্যাপি /catch.html# ফিল্টারক্যাচ পড়ুন । নিবন্ধটিও এখানে দেওয়া একাধিক ক্যাচ উত্তর পুনরুত্পাদন করে।
মমিবোট

47

.catchtry-catchবিবৃতিটির মতো কাজ করে , যার অর্থ আপনার কেবল শেষে একটি ক্যাচ দরকার:

repository.Query(getAccountByIdQuery)
        .then(convertDocumentToModel)
        .then(verifyOldPassword)
        .then(changePassword)
        .then(function(){
            res.status(200).send();
        })
        .catch(function(error) {
            if (/*see if error is not found error*/) {
                res.status(404).send({ error: "No account found with this Id" });
            } else if (/*see if error is verification error*/) {
                res.status(406).send({ OldPassword: error });
            } else {
                console.log(error);
                res.status(500).send({ error: "Unable to change password" });
            }
        });

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

8
কি এটা মূল্য জন্য @Grofit - Bluebird টাইপ ক্যাচ ছিল Petka (Esailija) 'র ধারণা নিয়ে :) তাকে সন্তুষ্ট করার তারা একটি বাঞ্ছনীয় পদ্ধতির এখানে এসেছি কোন প্রয়োজন নেই শুরু করার। আমি মনে করি যে তিনি আপনাকে বিভ্রান্ত করতে চাননি যেহেতু জেএস-এর অনেক লোক ধারণা সম্পর্কে খুব সচেতন নয়।
বেনজামিন গ্রুইনবাউম

17

আমি ভাবছি যে আমার পক্ষে কোনও উপায় আছে যাতে কোনওভাবে ত্রুটির উপর ভিত্তি করে একটি নির্দিষ্ট পয়েন্টে চেইনটি থামাতে বাধ্য করা হয়

না। আপনি সত্যিই একটি শৃঙ্খলের "শেষ" করতে পারবেন না, যদি না আপনি এমন ব্যতিক্রম শেষ না করেন যা বুদবুদ শেষ না হয়। কীভাবে এটি করা যায় তার জন্য বেনিয়ামিন গ্রুইনবাউমের উত্তর দেখুন ।

তার প্যাটার্নটির একটি আবিষ্কারটি ত্রুটির প্রকারের পার্থক্য না করা, তবে ত্রুটিযুক্ত ক্ষেত্রগুলি statusCodeএবং bodyক্ষেত্রগুলি যা একক, জেনেরিক .catchহ্যান্ডলার থেকে প্রেরণ করা যেতে পারে তা ব্যবহার করবে । আপনার অ্যাপ্লিকেশন কাঠামোর উপর নির্ভর করে, তার সমাধান যদিও পরিষ্কার হতে পারে।

বা ব্রাঞ্চিং আচরণের কিছু ফর্ম পেতে যদি এটির আরও ভাল উপায় থাকে

হ্যাঁ, আপনি প্রতিশ্রুতি দিয়ে শাখা করতে পারেন । তবে, এর অর্থ চেইনটি ছেড়ে বাসা বাঁধতে "ফিরে যাও" - ঠিক যেমন আপনি যদি নেস্ট করে থাকেন তবে অন্যথায় বা চেষ্টা করার বক্তব্য:

repository.Query(getAccountByIdQuery)
.then(function(account) {
    return convertDocumentToModel(account)
    .then(verifyOldPassword)
    .then(function(verification) {
        return changePassword(verification)
        .then(function() {
            res.status(200).send();
        })
    }, function(verificationError) {
        res.status(406).send({ OldPassword: error });
    })
}, function(accountError){
    res.status(404).send({ error: "No account found with this Id" });
})
.catch(function(error){
    console.log(error);
    res.status(500).send({ error: "Unable to change password" });
});

5

আমি এইভাবে করছি:

শেষ পর্যন্ত তুমি ছেড়ে দাও। আপনার চেইনের মাঝখানে যখন ঘটে তখন কেবল একটি ত্রুটি নিক্ষেপ করুন।

    repository.Query(getAccountByIdQuery)
    .then((resultOfQuery) => convertDocumentToModel(resultOfQuery)) //inside convertDocumentToModel() you check for empty and then throw new Error('no_account')
    .then((model) => verifyOldPassword(model)) //inside convertDocumentToModel() you check for empty and then throw new Error('no_account')        
    .then(changePassword)
    .then(function(){
        res.status(200).send();
    })
    .catch((error) => {
    if (error.name === 'no_account'){
        res.status(404).send({ error: "No account found with this Id" });

    } else  if (error.name === 'wrong_old_password'){
        res.status(406).send({ OldPassword: error });

    } else {
         res.status(500).send({ error: "Unable to change password" });

    }
});

আপনার অন্যান্য ক্রিয়াকলাপগুলি সম্ভবত এটির মতো দেখতে লাগবে:

function convertDocumentToModel(resultOfQuery) {
    if (!resultOfQuery){
        throw new Error('no_account');
    } else {
    return new Promise(function(resolve) {
        //do stuff then resolve
        resolve(model);
    }                       
}

4

সম্ভবত পার্টিতে কিছুটা দেরি হলেও .catchএখানে দেখানো অনুসারে বাসা বাঁধাই সম্ভব :

মোজিলা বিকাশকারী নেটওয়ার্ক - প্রতিশ্রুতি ব্যবহার করে

সম্পাদনা করুন: আমি এটি জমা দিয়েছি কারণ এটি সাধারণভাবে জিজ্ঞাসিত কার্যকারিতা সরবরাহ করে। তবে এটি এই বিশেষ ক্ষেত্রে হয় না। কারণ ইতিমধ্যে অন্যদের দ্বারা বিশদ হিসাবে ব্যাখ্যা করা হয়েছে, .catchত্রুটিটি পুনরুদ্ধার করার কথা। উদাহরণস্বরূপ, আপনি একাধিক .catch কলব্যাকগুলিতে ক্লায়েন্টকে প্রতিক্রিয়া পাঠাতে পারবেন না কারণ কোনওরূপে .catchকোনও স্পষ্ট ছাড়াই এটির return সমাধান করে undefinedনা, .thenআপনার চেইনটি সত্যিকার অর্থে সমাধান না হওয়া সত্ত্বেও ট্রিগার শুরু করে, সম্ভাব্যভাবে নিম্নলিখিতটি .catchট্রিগার এবং প্রেরণের কারণ ঘটায় ক্লায়েন্টের অন্য একটি প্রতিক্রিয়া, একটি ত্রুটি সৃষ্টি করে এবং সম্ভবত UnhandledPromiseRejectionআপনার পথ ছুঁড়েছে । আমি আশা করি এই বিভ্রান্তিকর বাক্যটি আপনার কাছে কিছুটা অর্থপূর্ণ হয়েছে।


1
পছন্দ করুন আমি আমার উত্তরটি প্রসারিত করে ব্যাখ্যা করেছিলাম কেন তার পছন্দসই আচরণটি বাসা
বাঁধানো

2

পরিবর্তে .then().catch()...আপনি করতে পারেন .then(resolveFunc, rejectFunc)। আপনি যদি রাস্তায় জিনিসগুলি পরিচালনা করেন তবে এই প্রতিশ্রুতি শৃঙ্খলা আরও ভাল। এখানে আমি কীভাবে এটি আবার লিখব:

repository.Query(getAccountByIdQuery)
    .then(
        convertDocumentToModel,
        () => {
            res.status(404).send({ error: "No account found with this Id" });
            return Promise.reject(null)
        }
    )
    .then(
        verifyOldPassword,
        () => Promise.reject(null)
    )
    .then(
        changePassword,
        (error) => {
            if (error != null) {
                res.status(406).send({ OldPassword: error });
            }
            return Promise.Promise.reject(null);
        }
    )
    .then(
        _ => res.status(200).send(),
        error => {
            if (error != null) {
                console.error(error);
                res.status(500).send({ error: "Unable to change password" });
            }
        }
    );

নোট:if (error != null) একটি হ্যাক একটি বিট সাম্প্রতিকতম ত্রুটি সাথে ইন্টারঅ্যাক্ট হয়।


1

আমি মনে করি উপরের বেনিয়ামিন গ্রুইনবাউমের উত্তরটি একটি জটিল যুক্তিযুক্ত ক্রমের সর্বোত্তম সমাধান, তবে সহজ পরিস্থিতিগুলির জন্য এখানে আমার বিকল্প। পরবর্তী কোনও বা বিবৃতি এড়াতে আমি কেবল একটি errorEncounteredপতাকা ব্যবহার করি । সুতরাং এটি দেখতে এই মত হবে:return Promise.reject()thencatch

let errorEncountered = false;
someCall({
  /* do stuff */
})
.catch({
  /* handle error from someCall*/
  errorEncountered = true;
  return Promise.reject();
})
.then({
  /* do other stuff */
  /* this is skipped if the preceding catch was triggered, due to Promise.reject */
})
.catch({
  if (errorEncountered) {
    return;
  }
  /* handle error from preceding then, if it was executed */
  /* if the preceding catch was executed, this is skipped due to the errorEncountered flag */
});

আপনার যদি দু'বারের বেশি / ক্যাচ জোড় থাকে তবে আপনার সম্ভবত বেনজামিন গ্রুয়েনবাউমের দ্রবণটি ব্যবহার করা উচিত। তবে এটি একটি সাধারণ সেট আপের জন্য কাজ করে।

নোট করুন যে ফাইনালটি catchকেবল তার return;পরিবর্তে রয়েছে return Promise.reject();, কারণ এর পরে আর কিছু নেই thenযে আমাদের এড়াতে হবে, এবং এটি একটি অনিচ্ছাকৃত প্রতিশ্রুতি প্রত্যাখ্যান হিসাবে গণ্য হবে, যা নোড পছন্দ করেন না। উপরে লেখা আছে, ফাইনালটি catchশান্তিপূর্ণভাবে সমাধান হওয়া প্রতিশ্রুতি ফিরিয়ে দেবে।

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