জাভাস্ক্রিপ্ট প্রতিশ্রুতি - বনাম থ্রো প্রত্যাখ্যান


384

আমি এই বিষয়ে বেশ কয়েকটি নিবন্ধ পড়েছি, তবে এখনও Promise.rejectত্রুটি নিক্ষেপ করার মধ্যে কোনও পার্থক্য রয়েছে কিনা তা আমার কাছে স্পষ্ট নয় । উদাহরণ স্বরূপ,

Promise.reject ব্যবহার করা হচ্ছে Using

return asyncIsPermitted()
    .then(function(result) {
        if (result === true) {
            return true;
        }
        else {
            return Promise.reject(new PermissionDenied());
        }
    });

নিক্ষেপ ব্যবহার

return asyncIsPermitted()
    .then(function(result) {
        if (result === true) {
            return true;
        }
        else {
            throw new PermissionDenied();
        }
    });

আমার পছন্দটি throwকেবল এটি খাটো হওয়ার কারণে ব্যবহার করা, তবে ভাবছিলাম যে একে অপরের উপরের কোনও সুবিধা আছে কিনা।


9
উভয় পদ্ধতিই একই প্রতিক্রিয়া তৈরি করে। .then()হ্যান্ডলার নিক্ষিপ্ত ব্যতিক্রম ক্যাচ এবং একটি প্রত্যাখ্যাত প্রতিশ্রুতি সেটিকে স্বয়ংক্রিয়ভাবে সক্রিয়। যেহেতু আমি পড়েছি যে নিক্ষিপ্ত ব্যতিক্রমগুলি কার্যকর করতে খুব দ্রুত হয় না, তাই আমি অনুমান করব যে প্রত্যাখ্যাত প্রতিশ্রুতি ফিরিয়ে দেওয়া কার্যকর করতে কিছুটা দ্রুত হতে পারে তবে এটি যদি জানা গুরুত্বপূর্ণ ছিল তবে আপনাকে একাধিক আধুনিক ব্রাউজারে একটি পরীক্ষা করতে হবে। আমি ব্যক্তিগতভাবে ব্যবহার করি throwকারণ আমি পাঠযোগ্যতা পছন্দ করি।
jender00

@ ওয়েবেডুভেট প্রতিশ্রুতি দিয়ে নয় - তারা নিক্ষেপ দিয়ে কাজ করার জন্য ডিজাইন করা হয়েছে।
জুইস

15
একটি খারাপ দিক throwহ'ল এটি যদি একটি সেটটাইমআউট হিসাবে অ্যাসিক্রোনাস কলব্যাকের মধ্যে থেকে ফেলে দেওয়া হয় তবে এটি প্রত্যাখ্যানিত প্রতিশ্রুতিতে পরিণত হয় না। jsfiddle.net/m07van33 @ ব্লন্ডি আপনার উত্তরটি সঠিক ছিল।
কেভিন বি

@ জিউস এটির অর্থ এটি ভাল নয়;)
ওয়েবডুভেট

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

উত্তর:


344

একটি বনাম অন্য বনাম ব্যবহার করার কোনও সুবিধা নেই, তবে, একটি নির্দিষ্ট ক্ষেত্রে রয়েছে যেখানে throwকাজ করবে না। তবে এই মামলাগুলি স্থির করা যায়।

আপনি যে কোনও সময় কোনও প্রতিশ্রুতি কলব্যাকের ভিতরে থাকলে আপনি ব্যবহার করতে পারেন throw। তবে আপনি যদি অন্য কোনও অ্যাসিনক্রোনাস কলব্যাক করেন তবে আপনাকে অবশ্যই ব্যবহার করতে হবে reject

উদাহরণস্বরূপ, এটি ধরাটিকে ট্রিগার করবে না:

new Promise(function() {
  setTimeout(function() {
    throw 'or nah';
    // return Promise.reject('or nah'); also won't work
  }, 1000);
}).catch(function(e) {
  console.log(e); // doesn't happen
});

পরিবর্তে আপনি একটি অমীমাংসিত প্রতিশ্রুতি এবং একটি অনাবৃত ব্যতিক্রম বাকি রয়েছেন। এটি এমন একটি ক্ষেত্রে যেখানে আপনি পরিবর্তে ব্যবহার করতে চান reject। তবে আপনি এটি দুটি উপায়ে ঠিক করতে পারেন।

  1. সময়সীমার ভিতরে মূল প্রতিজ্ঞার প্রত্যাখ্যান ফাংশনটি ব্যবহার করে:

new Promise(function(resolve, reject) {
  setTimeout(function() {
    reject('or nah');
  }, 1000);
}).catch(function(e) {
  console.log(e); // works!
});

  1. সময়সীমা প্রচারের মাধ্যমে:

function timeout(duration) { // Thanks joews
  return new Promise(function(resolve) {
    setTimeout(resolve, duration);
  });
}

timeout(1000).then(function() {
  throw 'worky!';
  // return Promise.reject('worky'); also works
}).catch(function(e) {
  console.log(e); // 'worky!'
});


54
অপরিবর্তিত অ্যাসিঙ্ক কলব্যাকের ভিতরে যে জায়গাগুলি আপনি ব্যবহার করতে পারবেন না throw error, আপনি এটিও ব্যবহার করতে পারবেন না return Promise.reject(err)যা ওপি আমাদের সাথে তুলনা করতে বলেছিল mentioning মূলত এই কারণেই আপনাকে প্রতিশ্রুতির অভ্যন্তরে অ্যাসিঙ্ক কলব্যাক রাখা উচিত নয়। অ্যাসিঙ্কের সমস্ত কিছু প্রচার করুন এবং তারপরে আপনার এই প্রতিবন্ধকতা নেই।
jਫਰ00

9
"তবে, আপনি যদি অন্য কোনও কলব্যাকে থাকেন তবে" সত্যই "হওয়া উচিত" তবে আপনি যদি অন্য কোনও ধরণের অ্যাসিনক্রোনাস কলব্যাকের মধ্যে থাকেন তবে "। কলব্যাকগুলি সিঙ্ক্রোনাস হতে পারে (উদাহরণস্বরূপ Array#forEach) এবং এর সাথে, তাদের ভিতরে ফেলে দেওয়া কাজ করবে।
ফলিক্স সাপরেলি

2
@ কেভিনব এই লাইনগুলি পড়ছেন "একটি নির্দিষ্ট ক্ষেত্রে রয়েছে যেখানে থ্রো কাজ করবে না।" এবং "আপনি যখনই কোনও প্রতিশ্রুতি কলব্যাকের অভ্যন্তরে রয়েছেন, আপনি থ্রো ব্যবহার করতে পারেন However তবে, আপনি যদি অন্য কোনও অ্যাসিনক্রোনাস কলব্যাক করেন তবে আপনাকে অবশ্যই প্রত্যাখ্যান করতে হবে use" আমি একটি অনুভূতি পেয়েছি যে উদাহরণ স্নিপেটগুলি এমন কেসগুলি দেখায় যেখানে throwকাজ করবে না এবং তার পরিবর্তে Promise.rejectআরও ভাল পছন্দ। তবে স্নিপেটগুলি two দুটি পছন্দের যে কোনওটির সাথেই অবিচ্ছিন্ন থাকে এবং আপনি যা পছন্দ করেন তা নির্বিশেষে একই ফলাফল দেয়। আমি কিছু অনুপস্থিত করছি?
আনশুল

2
হ্যাঁ. যদি আপনি একটি সেটটাইমআউটে থ্রো ব্যবহার করেন তবে ক্যাচটি কল করা হবে না। আপনার অবশ্যই কলব্যাকটি rejectপাস করা উচিত new Promise(fn)
কেভিন বি

2
@ কেভিনবি পাশে থাকার জন্য ধন্যবাদ ওপি প্রদত্ত উদাহরণে উল্লেখ করেছেন যে তিনি বিশেষভাবে তুলনা করতে চেয়েছিলেন return Promise.reject()এবং throw। তিনি কনস্ট্রাক্টে rejectপ্রদত্ত কলব্যাকের কথা উল্লেখ করেন না new Promise(function(resolve, reject))। সুতরাং যখন আপনার দুটি স্নিপেটগুলি ঠিকঠাকভাবে প্রদর্শন করে যে আপনি যখন সমাধান কলব্যাকটি ব্যবহার করবেন তখন ওপি-র প্রশ্নটি এটি ছিল না।
আনশুল

200

আরেকটি বিষয় অনুপস্থিত যে reject() না নিয়ন্ত্রণ প্রবাহ বিনষ্ট একটি মত returnবিবৃতি আছে। বিপরীতে throwনিয়ন্ত্রণ প্রবাহ বন্ধ করে দেয়।

উদাহরণ:

new Promise((resolve, reject) => {
  throw "err";
  console.log("NEVER REACHED");
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));

বনাম

new Promise((resolve, reject) => {
  reject(); // resolve() behaves similarly
  console.log("ALWAYS REACHED"); // "REJECTED" will print AFTER this
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));


50
ঠিক আছে পয়েন্টটি ঠিক তবে তুলনাটি জটিল। কারণ সাধারণত আপনার লেখার মাধ্যমে আপনার প্রত্যাখ্যাত প্রতিশ্রুতি ফিরিয়ে দেওয়া উচিত return reject(), সুতরাং পরবর্তী লাইনটি চলবে না।
এজেড

7
আপনি কেন এটি ফিরিয়ে দিতে চান?
lukyer

31
এই ক্ষেত্রে, return reject()কেবলমাত্র একটি সংক্ষিপ্তকরণ reject(); returnহ'ল আপনি যা চান তা প্রবাহ বন্ধ করতে হবে ate এক্সিকিউটারের রিটার্ন মান (ফাংশনটি প্রেরণ করা new Promise) ব্যবহৃত হয় না, তাই এটি নিরাপদ।
ফলিক্স সাপরেলি

47

হ্যাঁ, সবচেয়ে বড় পার্থক্য হ'ল প্রত্যাখ্যান করা একটি কলব্যাক ফাংশন যা প্রতিশ্রুতি প্রত্যাখ্যানের পরে সম্পাদিত হয়, অন্যদিকে নিক্ষেপকে সংবিধান হিসাবে ব্যবহার করা যায় না cannot আপনি ব্যবহার প্রত্যাখ্যান বেছে আপনার কোড অ্যাসিঙ্ক্রোনাস ফ্যাশন স্বাভাবিকভাবে চালাতে যেহেতু অব্যাহত থাকবে থ্রো সমাধানকারী ফাংশন (এই ফাংশন অবিলম্বে চালানো হবে) পূরণ করার অগ্রাধিকার হবে।

আমি দেখেছি এমন একটি উদাহরণ যা আমার পক্ষে সমস্যাটি পরিষ্কার করতে সহায়তা করেছিল তা হল আপনি প্রত্যাখ্যানের সাথে টাইমআউট ফাংশন সেট করতে পারেন, উদাহরণস্বরূপ:

new Promise(_, reject) {
 setTimeout(reject, 3000);
});

উপরের থ্রো দিয়ে লেখা সম্ভব হত না।

আপনার ছোট উদাহরণে পার্থক্যটি পৃথক নয় তবে আরও জটিল অ্যাসিনক্রোনাস ধারণার সাথে যখন আচরণ করা হয় তখন উভয়ের মধ্যে পার্থক্য কঠোর হতে পারে।


1
এটি একটি মূল ধারণার মতো শোনাচ্ছে তবে আমি এটি লিখিত হিসাবে বুঝতে পারি না। প্রতিশ্রুতিতে এখনও খুব নতুন, আমার ধারণা।
ডেভিড স্পেক্টর

43

টিএলডিআর: কোনও ফাংশন ব্যবহার করা শক্ত যখন এটি কখনও কখনও প্রতিশ্রুতি দেয় এবং কখনও কখনও ব্যতিক্রম ছুঁড়ে দেয়। অ্যাসিঙ্ক ফাংশন লেখার সময়, প্রত্যাখ্যাত প্রতিশ্রুতি ফিরে দিয়ে ব্যর্থতার সংকেত দেওয়া পছন্দ করুন

আপনার নির্দিষ্ট উদাহরণ তাদের মধ্যে কিছু গুরুত্বপূর্ণ পার্থক্যকে আবদ্ধ করে:

যেহেতু আপনি কোনও প্রতিশ্রুতি শৃঙ্খলার অভ্যন্তরে পরিচালনা করতে ত্রুটি করছেন , নিক্ষিপ্ত ব্যতিক্রমগুলি স্বয়ংক্রিয়ভাবে প্রত্যাখ্যাত প্রতিশ্রুতিতে রূপান্তরিত হয়। এগুলি ব্যাখ্যা করতে পারে যে তারা কেন বিনিময়যোগ্য বলে মনে হচ্ছে - তারা তা নয়।

নীচের পরিস্থিতি বিবেচনা করুন:

checkCredentials = () => {
    let idToken = localStorage.getItem('some token');
    if ( idToken ) {
      return fetch(`https://someValidateEndpoint`, {
        headers: {
          Authorization: `Bearer ${idToken}`
        }
      })
    } else {
      throw new Error('No Token Found In Local Storage')
    }
  }

এটি একটি অ্যান্টি-প্যাটার্ন হবে কারণ আপনার তখন অ্যাসিঙ্ক এবং সিঙ্ক উভয় ত্রুটির ক্ষেত্রে সমর্থন করা দরকার। এটি দেখতে কিছুটা দেখতে লাগবে:

try {
  function onFulfilled() { ... do the rest of your logic }
  function onRejected() { // handle async failure - like network timeout }
  checkCredentials(x).then(onFulfilled, onRejected);
} catch (e) {
  // Error('No Token Found In Local Storage')
  // handle synchronous failure
} 

ভাল নয় এবং ঠিক এখানেই Promise.reject(বিশ্বব্যাপী সুযোগে উপলব্ধ) উদ্ধার করতে আসে এবং কার্যকরভাবে এটিকে পৃথক করে throw। রিফ্যাক্টরটি এখন পরিণত হয়:

checkCredentials = () => {
  let idToken = localStorage.getItem('some_token');
  if (!idToken) {
    return Promise.reject('No Token Found In Local Storage')
  }
  return fetch(`https://someValidateEndpoint`, {
    headers: {
      Authorization: `Bearer ${idToken}`
    }
  })
}

এটি এখন আপনাকে catch()নেটওয়ার্ক ব্যর্থতা এবং টোকেনের অভাবে সিঙ্ক্রোনাস ত্রুটি যাচাইয়ের জন্য কেবল একটি ব্যবহার করতে দেয় :

checkCredentials()
      .catch((error) => if ( error == 'No Token' ) {
      // do no token modal
      } else if ( error === 400 ) {
      // do not authorized modal. etc.
      }

1
তবে অপের উদাহরণ সর্বদা একটি প্রতিশ্রুতি দেয়। প্রশ্নটি আপনাকে ব্যবহার করা উচিত কিনা Promise.rejectবা throwআপনি প্রত্যাখ্যাত প্রতিশ্রুতি (যে প্রতিশ্রুতি পরের দিকে ঝাঁপিয়ে পড়বে .catch()) ফিরিয়ে দিতে চান তা উল্লেখ করছে ।
মার্কোস পেরেইরা

@ ম্যাক্সওয়েল - আমি আপনার উদাহরণ পছন্দ করি। একই সময়ে যদি আনার সময় আপনি একটি ক্যাচ যুক্ত করবেন এবং এতে আপনি ব্যতিক্রম ছুঁড়ে ফেলেন তবে আপনি চেষ্টা করে ব্যবহার করতে পারবেন নিরাপদে ... ধরুন ... ব্যতিক্রম প্রবাহে কোনও নিখুঁত বিশ্ব নেই, তবে আমি মনে করি এটি ব্যবহার করে একক প্যাটার্নটি বোঝায়, এবং নিদর্শনগুলির সংমিশ্রণ নিরাপদ নয় (আপনার প্যাটার্ন বনাম অ্যান্টি-প্যাটার্ন সাদৃশ্যের সাথে সংযুক্ত)
ব্যবহারকারী 3053247

1
দুর্দান্ত উত্তর কিন্তু আমি এখানে একটি ত্রুটি খুঁজে পেয়েছি - এই প্যাটার্নটি অনুমান করে যে সমস্ত ত্রুটি একটি প্রতিশ্রুতি.রেজেক্ট ফিরিয়ে দিয়ে পরিচালিত হয় - সমস্ত অপ্রত্যাশিত ত্রুটির সাথে কী ঘটে যা কেবল চেক ক্রেডিটেন্সিয়াল () থেকে ফেলে দেওয়া যেতে পারে?
চেনপ

1
হ্যাঁ আপনি ঠিকই @ চেনোপ - এই অপ্রত্যাশিত ত্রুটিগুলি ধরতে আপনাকে চেষ্টা /
আবদ্ধ করার

আমি @ ম্যাক্সওয়েলের ক্ষেত্রে বুঝতে পারি না। আপনি কেবল এটির মতো কাঠামো তৈরি করতে পারেন নি checkCredentials(x).then(onFulfilled).catch(e) {}এবং catchপ্রত্যাখ্যান কেস এবং নিক্ষিপ্ত ত্রুটির ক্ষেত্রে উভয়ই হ্যান্ডেলটি পেতে পারেন ?
বেন হুইলার 15

5

চেষ্টা করার জন্য একটি উদাহরণ। কেবলমাত্র ভার্সনথ্রোকে থ্রো-র পরিবর্তে বাতিল করতে ব্যবহার করতে মিথ্যাতে পরিবর্তন করুন।

const isVersionThrow = true

class TestClass {
  async testFunction () {
    if (isVersionThrow) {
      console.log('Throw version')
      throw new Error('Fail!')
    } else {
      console.log('Reject version')
      return new Promise((resolve, reject) => {
        reject(new Error('Fail!'))
      })
    }
  }
}

const test = async () => {
  const test = new TestClass()
  try {
    var response = await test.testFunction()
    return response 
  } catch (error) {
    console.log('ERROR RETURNED')
    throw error 
  }  
}

test()
.then(result => {
  console.log('result: ' + result)
})
.catch(error => {
  console.log('error: ' + error)
})

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