আমি কেন একটি প্রতিশ্রুতি। ক্যাচ হ্যান্ডলারের ভিতরে ফেলতে পারি না?


127

কেন আমি কেবল Errorক্যাচ কলব্যাকের অভ্যন্তরে কোনও ছোঁড়াতে পারি না এবং প্রক্রিয়াটিকে ত্রুটিটি এমনভাবে পরিচালনা করতে পারি যেন তা অন্য কোনও সুযোগে থাকে?

আমি যদি কিছু না করি তবে console.log(err)মুদ্রিত হয়ে যায় এবং কী ঘটেছিল সে সম্পর্কে আমি কিছুই জানি না। প্রক্রিয়া সবে শেষ ...

উদাহরণ:

function do1() {
    return new Promise(function(resolve, reject) {
        throw new Error('do1');
        setTimeout(resolve, 1000)
    });
}

function do2() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            reject(new Error('do2'));
        }, 1000)
    });
}

do1().then(do2).catch(function(err) {
    //console.log(err.stack); // This is the only way to see the stack
    throw err; // This does nothing
});

কলব্যাকগুলি যদি মূল থ্রেডে কার্যকর করা হয় তবে Errorব্ল্যাকহোল দিয়ে কেন গ্রাস করে?


11
এটি একটি ব্ল্যাকহোল দ্বারা গ্রাস করা হয় না। এটি যে প্রতিশ্রুতি দেয় তা প্রত্যাখ্যান করে .catch(…)
বার্গি


পরিবর্তে .catch((e) => { throw new Error() }), লিখুন .catch((e) => { return Promise.reject(new Error()) })বা সহজভাবে.catch((e) => Promise.reject(new Error()))
ছারভে

1
আপনার মন্তব্যে সমস্ত চিত্র স্নিপেটের ঠিক একইরকম আচরণ রয়েছে, প্রাথমিকভাবে বাদে স্পষ্টতই সবচেয়ে পরিষ্কার except
Гринько

উত্তর:


157

অন্যরা যেমন ব্যাখ্যা করেছে, "ব্ল্যাকহোল" কারণ .catchএটি একটি অনাহুত প্রতিশ্রুতি দিয়ে শৃঙ্খলা চালিয়ে যাচ্ছে এবং আপনার আর কোনও ক্যাচ নেই, যার ফলে একটি নির্বিঘ্ন শৃঙ্খলা তৈরি হয়, যা ত্রুটিগুলি গ্রাস করে (খারাপ!)

কী ঘটছে তা দেখতে আরও একটি ক্যাচ যুক্ত করুন:

do1().then(do2).catch(function(err) {
    //console.log(err.stack); // This is the only way to see the stack
    throw err; // Where does this go?
}).catch(function(err) {
    console.log(err.stack); // It goes here!
});

একটি চেইনের মাঝখানে একটি ক্যাচ কার্যকর যখন আপনি চেইনটি ব্যর্থ পদক্ষেপের পরেও এগিয়ে যেতে চান, তবে তথ্য লগইন বা ক্লিনআপ স্টেপগুলির মতো কাজগুলি করার পরে ব্যর্থতা অব্যাহত রাখতে পুনরায় নিক্ষেপ কার্যকর , সম্ভবত কোন ত্রুটি পরিবর্তন করে নিক্ষেপ করা হয়

কৌতুক

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

.catch(function(err) { setTimeout(function() { throw err; }); });

এমনকি লাইন নম্বরগুলি টিকে থাকে, সুতরাং ওয়েব কনসোলের লিঙ্কটি আমাকে সরাসরি ফাইল এবং লাইনে নিয়ে যায় যেখানে (মূল) ত্রুটি ঘটেছে।

কেন এটি কাজ করে

প্রতিশ্রুতি পূর্ণতা বা প্রত্যাখ্যান হ্যান্ডলার হিসাবে ডাকা একটি কার্যক্রমে কোনও ব্যতিক্রম স্বয়ংক্রিয়ভাবে আপনি যে প্রতিশ্রুতি ফিরে আসবেন বলে প্রত্যাখ্যান করে তা রূপান্তরিত হয়। প্রতিশ্রুতি কোড যা আপনার ফাংশনটিকে কল করে এটি এটি যত্ন করে।

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


3
জিব, এটি একটি আকর্ষণীয় কৌশল, আপনি আমাকে বুঝতে সাহায্য করতে পারেন কেন এটি কাজ করে?
ব্রায়ান কিথ

8
সেই কৌশল সম্পর্কে: আপনি নিক্ষেপ করতে চান বলে ছুড়ে ফেলছেন, তাই কেন কেবল সরাসরি লগইন করবেন না? এই কৌশলটি 'এলোমেলো' সময়ে একটি অপ্রকাশনীয় ত্রুটি ছুঁড়ে ফেলবে .... তবে ব্যতিক্রমগুলির পুরো ধারণাটি (এবং যেভাবে তাদের সাথে ডিলের প্রতিশ্রুতি দেয়) ত্রুটিটি ধরা এবং এটি মোকাবেলা করার জন্য আহ্বানকারীকে তার দায়বদ্ধ করে তোলা। এই কোডটি কার্যকরভাবে কলারের পক্ষে ত্রুটিগুলি মোকাবেলা করা অসম্ভব করে তোলে। আপনার জন্য এটি হ্যান্ডেল করার জন্য কেন একটি ফাংশন তৈরি করবেন না? function logErrors(e){console.error(e)}তারপরে এটি ব্যবহার করুন do1().then(do2).catch(logErrors)। উত্তরটি নিজেই দুর্দান্ত বিটিডব্লিউ, +1
স্টিজন ডি উইট

3
@ জিব আমি একটি এডাব্লুএস ল্যাম্বদা লিখছি যার মধ্যে অনেকগুলি প্রতিশ্রুতি রয়েছে যা এই ক্ষেত্রে কম-বেশি সংযুক্ত রয়েছে। ত্রুটির ক্ষেত্রে এডাব্লুএসের এলার্ম এবং বিজ্ঞপ্তিগুলি কাজে লাগাতে ল্যাম্বডা ক্র্যাশটিকে ত্রুটি ছুঁড়ে ফেলতে হবে (আমার ধারণা)। কৌশলটি কি এটি পাওয়ার একমাত্র উপায়?
মাস্কিগো

2
@ স্টিজেডেভিট আমার ক্ষেত্রে, আমি window.onerrorইভেন্ট হ্যান্ডলারে আমার সার্ভারে ত্রুটির বিবরণ প্রেরণের চেষ্টা করছিলাম । setTimeoutকৌতুকটি করেই এটি করা যায়। অন্যথায় window.onerrorপ্রতিশ্রুতিতে ঘটে যাওয়া ত্রুটিগুলি সম্পর্কে কোনও কিছুই শুনবে না।
হুডিডিট

1
@hudidit এখনও, wheter এটা console.logবা postErrorToServer, আপনি শুধু কি করা দরকার তা করতে পারেন। যে কোনও window.onerrorকোডেই থাকুক না কেন এটি আলাদা ফাংশন হিসাবে চিহ্নিত করা যায় না এবং 2 জায়গা থেকে কল করা যায় না। এটি সম্ভবত setTimeoutলাইনটি আরও ছোট হবে ।
স্টিজন ডি উইট

46

এখানে গুরুত্বপূর্ণ জিনিস

  1. উভয় thenএবং catchফাংশনগুলি নতুন প্রতিশ্রুতি দেয় return

  2. হয় নিক্ষেপ বা স্পষ্টভাবে প্রত্যাখ্যান, বর্তমান প্রতিশ্রুতি প্রত্যাখাত রাজ্যে সরানো হবে।

  3. যেহেতু thenএবং catchনতুন প্রতিশ্রুতি অবজেক্টগুলি ফিরিয়ে দেয়, সেগুলি বেঁধে রাখা যায়।

  4. যদি আপনি কোনও প্রতিশ্রুতি হ্যান্ডলার ( thenবা catch) এর ভিতরে ফেলে দেন বা প্রত্যাখ্যান করেন তবে এটি পরবর্তী প্রত্যাখ্যানের হাতলটিতে শৃঙ্খলাবদ্ধভাবে নিচে নামানো হবে।

  5. Jender00 দ্বারা উল্লিখিত হিসাবে, thenএবং catchহ্যান্ডলারগুলি একযোগে কার্যকর করা হয় না। যখন কোনও হ্যান্ডলার ছুড়ে দেয় তখন তা অবিলম্বে শেষ হয়ে যাবে। সুতরাং, স্ট্যাকটি অযৌক্তিক হবে এবং ব্যতিক্রমটি হারিয়ে যাবে। সে কারণেই একটি ব্যতিক্রম ছোঁড়া বর্তমান প্রতিশ্রুতি প্রত্যাখ্যান করে।


আপনার ক্ষেত্রে, আপনি do1কোনও Errorবস্তু নিক্ষেপ করে ভিতরে প্রত্যাখ্যান করছেন । এখন, বর্তমান প্রতিশ্রুতি প্রত্যাখ্যাত অবস্থায় থাকবে এবং নিয়ন্ত্রণটি পরবর্তী হ্যান্ডলারের কাছে স্থানান্তরিত হবে, যা thenআমাদের ক্ষেত্রে।

যেহেতু thenহ্যান্ডলারের একটি প্রত্যাখ্যান হ্যান্ডলার নেই, তাই do2একেবারেই কার্যকর করা হবে না। আপনি console.logএটির ভিতরে এটি ব্যবহার করে নিশ্চিত করতে পারেন । যেহেতু বর্তমান প্রতিশ্রুতিতে একটি প্রত্যাখ্যান হ্যান্ডলার নেই, এটি পূর্ববর্তী প্রতিশ্রুতি থেকে প্রত্যাখ্যান মান সহও প্রত্যাখ্যাত হবে এবং নিয়ন্ত্রণটি পরবর্তী হ্যান্ডলারের কাছে স্থানান্তরিত হবে যা catch

catchযেমন একটি প্রত্যাখ্যান হ্যান্ডলার হিসাবে , আপনি যখন console.log(err.stack);এটির অভ্যন্তরীণ কাজ করেন, আপনি ত্রুটি স্ট্যাকের ট্রেস দেখতে সক্ষম হন। এখন, আপনি Errorএটি থেকে কোনও বস্তু নিক্ষেপ করছেন তাই প্রদত্ত প্রতিশ্রুতিও catchপ্রত্যাখ্যাত অবস্থায় থাকবে।

যেহেতু আপনি কোনও প্রত্যাখ্যান হ্যান্ডলারটিকে সংযুক্ত করেননি catch, তাই আপনি প্রত্যাখ্যানটি পর্যবেক্ষণ করতে পারবেন না।


আপনি চেইনটি বিভক্ত করতে পারেন এবং এটি আরও ভাল করে বুঝতে পারেন

var promise = do1().then(do2);

var promise1 = promise.catch(function (err) {
    console.log("Promise", promise);
    throw err;
});

promise1.catch(function (err) {
    console.log("Promise1", promise1);
});

আউটপুট আপনি পাবেন কিছু হবে

Promise Promise { <rejected> [Error: do1] }
Promise1 Promise { <rejected> [Error: do1] }

ইনসাইড catchহ্যান্ডলার 1, তোমাদের মধ্যে মান পাচ্ছেন promiseঅবজেক্ট হিসেবে প্রত্যাখ্যাত।

একইভাবে, catchহ্যান্ডলার 1 দ্বারা প্রদত্ত প্রতিশ্রুতিও একই ত্রুটির সাথে promiseপ্রত্যাখ্যান করা হয়েছিল যা দিয়ে প্রত্যাখ্যাত হয়েছিল এবং আমরা দ্বিতীয় catchহ্যান্ডলারে এটি পর্যবেক্ষণ করছি ।


3
.then()হ্যান্ডলারগুলি অ্যাসিঙ্ক (এগুলি কার্যকর করার আগে স্ট্যাকটি অযৌক্তিক হয়) এগুলিও যুক্তিযুক্ত হতে পারে তাই তাদের অভ্যন্তরীণ ব্যতিক্রমগুলি প্রত্যাখ্যানিত করে তুলতে হবে, অন্যথায় তাদের ধরতে কোনও ব্যতিক্রম হ্যান্ডলার থাকবে না।
jفر00

7

আমি setTimeout()উপরে বিস্তারিত পদ্ধতি চেষ্টা করেছি ...

.catch(function(err) { setTimeout(function() { throw err; }); });

বিরক্তিকরভাবে, আমি এটি সম্পূর্ণরূপে অকেজো হতে পেরেছি। এটি একটি অ্যাসিক্রোনাস ত্রুটি নিক্ষেপ করার কারণে, আপনি এটি একটি try/catchবিবৃতিতে গুটিয়ে রাখতে পারবেন না , কারণ catchসময় ত্রুটি নিক্ষেপ হওয়ার পরে উইলটি শুনতে শুনতে বন্ধ করে দিয়েছে।

আমি কেবল শ্রোতাদের ব্যবহারে ফিরে গিয়েছিলাম যা পুরোপুরি কাজ করেছিল এবং কারণ এটি জাভাস্ক্রিপ্টটি কীভাবে ব্যবহার করা হয় তা অত্যন্ত পরীক্ষামূলক।

return new Promise((resolve, reject) => {
    reject("err");
}).catch(err => {
    this.emit("uncaughtException", err);

    /* Throw so the promise is still rejected for testing */
    throw err;
});

3
জেস্টের টাইমার মক রয়েছে যা এই পরিস্থিতিটি পরিচালনা করতে পারে।
jordanbtucker

2

অনুমান অনুসারে (দেখুন 3.III.d) :

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

এর অর্থ হ'ল আপনি যদি thenকার্যক্রমে ব্যতিক্রম নিক্ষেপ করেন তবে তা ধরা পড়বে এবং আপনার প্রতিশ্রুতি প্রত্যাখাত হবে। catchএখানে কোনও ধারণা রাখবেন না, এটি কেবল শর্টকাট.then(null, function() {})

আমার ধারণা আপনি আপনার কোডটিতে নিরবচ্ছিন্ন প্রত্যাখাতাগুলি লগ করতে চান। বেশিরভাগ প্রতিশ্রুতি গ্রন্থাগারগুলি unhandledRejectionএটির জন্য আগুন দেয়। এটি সম্পর্কে আলোচনা সহ প্রাসঙ্গিক টুকরোটি এখানে ।


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

1

আমি জানি যে এটি কিছুটা দেরি হয়ে গেছে, তবে আমি এই থ্রেডটি পেরিয়ে এসেছি এবং এর সমাধানগুলির কোনওটিই আমার পক্ষে বাস্তবায়ন করা সহজ ছিল না, তাই আমি আমার নিজের সাথে এলাম:

আমি একটি সামান্য সহায়ক ফাংশন যুক্ত করেছি যা একটি প্রতিশ্রুতি দেয়, যেমন:

function throw_promise_error (error) {
 return new Promise(function (resolve, reject){
  reject(error)
 })
}

তারপরে, যদি আমার কোনও প্রতিশ্রুতি শৃঙ্খলে আমার একটি নির্দিষ্ট জায়গা থাকে যেখানে আমি কোনও ত্রুটি ফেলতে চাই (এবং প্রতিশ্রুতি প্রত্যাখ্যান করি), তবে আমি কেবল আমার নির্মিত ত্রুটি দিয়ে উপরের ফাংশন থেকে ফিরে আসি, যেমন:

}).then(function (input) {
 if (input === null) {
  let err = {code: 400, reason: 'input provided is null'}
  return throw_promise_error(err)
 } else {
  return noterrorpromise...
 }
}).then(...).catch(function (error) {
 res.status(error.code).send(error.reason);
})

এইভাবে আমি প্রতিশ্রুতি-শৃঙ্খলার অভ্যন্তর থেকে অতিরিক্ত ত্রুটি ছুড়ে দেওয়ার নিয়ন্ত্রণে আছি। আপনি যদি 'স্বাভাবিক' প্রতিশ্রুতি ত্রুটিগুলিও পরিচালনা করতে চান, তবে আপনি 'স্ব-নিক্ষিপ্ত' ত্রুটিগুলি আলাদাভাবে চিকিত্সা করার জন্য আপনার ক্যাচটি প্রসারিত করবেন।

আশা করি এটি সহায়তা করে, এটি আমার প্রথম স্ট্যাকওভারফ্লো উত্তর!


Promise.reject(error)পরিবর্তে new Promise(function (resolve, reject){ reject(error) })(যা যাইহোক রিটার্ন বিবৃতি প্রয়োজন)
ফানকোডাব্যাট

0

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

...
  throw new Error('My error message');
})
.catch(function (err) {
  console.error(err.stack);
  process.exit(0);
});

1
না, এটি পর্যাপ্ত নয়, কারণ আপনার প্রতি প্রতিশ্রুতি শৃঙ্খলার শেষে আপনার এটি রাখা দরকার। বরং উপর হুক unhandledRejectionঘটনা
Bergi

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

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