`প্রত্যাশার প্রতিশ্রুতি` এবং` প্রত্যাবর্তনের প্রতিশ্রুতির মধ্যে পার্থক্য `


117

নীচের কোডের নমুনাগুলি দেওয়া, আচরণে কি কোনও পার্থক্য রয়েছে এবং যদি তাই হয় তবে এই পার্থক্যগুলি কী?

return await promise

async function delay1Second() {
  return (await delay(1000));
}

return promise

async function delay1Second() {
  return delay(1000);
}

যেহেতু আমি এটি বুঝতে পারি, প্রথমটিতে অ্যাসিঙ্ক ফাংশনটির মধ্যে ত্রুটি-পরিচালনা করা হবে এবং ত্রুটিগুলি অ্যাসিঙ্ক ফাংশনের প্রতিশ্রুতি থেকে বেরিয়ে আসবে। তবে দ্বিতীয়টির জন্য আরও একটি টিক লাগবে। এটা কি সঠিক?

এই স্নিপেট রেফারেন্সের জন্য কোনও প্রতিশ্রুতি ফিরিয়ে দেওয়ার জন্য কেবল একটি সাধারণ কাজ।

function delay(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

4
হ্যাঁ আমি আমার প্রশ্নটি সম্পাদনা করেছি কারণ আপনি আমার অর্থকে ভুল বুঝেছিলেন এবং আমি কী ভাবছিলাম তা এটি সত্যই উত্তর দেয় না।
পিতাজে

4
@ পিতাজে: আমি বিশ্বাস করি আপনি asyncআপনার দ্বিতীয় ( return promise) নমুনাটি সরিয়ে ফেলতে চেয়েছিলেন ।
স্টিফেন ক্লিয়ারি

4
@ পিটাজে: সেক্ষেত্রে, আপনার দ্বিতীয় উদাহরণটি একটি প্রতিশ্রুতি ফিরিয়ে দেবে যা একটি প্রতিশ্রুতি দিয়ে সমাধান করা হয়েছে। বরং বিজোড়।
স্টিফেন ক্লিয়ারি

5
jakearchibald.com/2017/await-vs-return-vs-return-await একটি চমৎকার নিবন্ধ যা পার্থক্যের সংক্ষিপ্তসার জানিয়েছে
Sanchit

4
@ স্টেফেনক্রিয়ারি, আমি এটিকে হোঁচট খেয়েছি এবং প্রথমে ঠিক একইরকম চিন্তা করেছি, একটি প্রতিশ্রুতি যে প্রতিশ্রুতি দিয়ে সমাধান করা হয়েছে তা এখানে বোঝা যায় না। কিন্তু এটি পরিণত হিসাবে, promise.then(() => nestedPromise)সমতল এবং "অনুসরণ" হবে nestedPromise। আমাদের # সি যেখানে সেখানে নেস্টেড কাজগুলি থেকে এটি আলাদা কী তা আকর্ষণীয় Unwrap। পার্শ্ব নোটে, এটি উপস্থিত রয়েছে যা কিছু আকর্ষণীয় শব্দার্থক পার্থক্য সহ কেবলমাত্র পরিবর্তে await somePromiseকল করে । Promise.resolve(somePromise).thensomePromise.then
নাসেরটিও

উত্তর:


165

বেশিরভাগ সময়, returnএবং এর মধ্যে কোনও পর্যবেক্ষণযোগ্য পার্থক্য নেই return await। উভয় সংস্করণে delay1Secondঠিক একই পর্যবেক্ষণযোগ্য আচরণ রয়েছে (তবে বাস্তবায়নের উপর নির্ভর করে return awaitসংস্করণটি কিছুটা বেশি মেমরি ব্যবহার করতে পারে কারণ একটি মধ্যবর্তী Promiseবস্তু তৈরি হতে পারে)।

তবে @PitaJ নির্দিষ্ট, সেখানে এক ক্ষেত্রে যেখানে একটি পার্থক্য আছে: যদি returnবা return awaitএকটি নেস্টেড হয় try- catchব্লক। এই উদাহরণ বিবেচনা করুন

async function rejectionWithReturnAwait () {
  try {
    return await Promise.reject(new Error())
  } catch (e) {
    return 'Saved!'
  }
}

async function rejectionWithReturn () {
  try {
    return Promise.reject(new Error())
  } catch (e) {
    return 'Saved!'
  }
}

প্রথম সংস্করণে, অ্যাসিঙ্ক ফাংশন ফলাফল প্রত্যাবর্তনের আগে প্রত্যাখ্যাত প্রতিশ্রুতির জন্য অপেক্ষা করে, যার ফলে প্রত্যাখ্যানটি একটি ব্যতিক্রমে রূপান্তরিত হয় এবং catchধারাটি পৌঁছায়; ফাংশনটি এইভাবে "সংরক্ষিত!" স্ট্রিংয়ের সমাধানের প্রতিশ্রুতি ফিরিয়ে দেবে।

ফাংশনের দ্বিতীয় সংস্করণটি যদিও অ্যাসিঙ্ক ফাংশনটির মধ্যে অপেক্ষা না করে প্রত্যাখ্যাত প্রতিশ্রুতিটি সরাসরি প্রত্যাবর্তন করে , যার অর্থ কেসটি ডাকা catchহয় না এবং তার পরিবর্তে কলার প্রত্যাখ্যান পায়।


সম্ভবত আরও উল্লেখ করুন যে স্ট্যাকের ট্রেসটি আলাদা হবে (এমনকি চেষ্টা / ধরা ছাড়াই)? আমার মনে হয় এই সমস্যাটি লোকেদের মধ্যে প্রায়শই উদাহরণ হিসাবে দেখা যায়:]
বেনজামিন গ্রুয়েনবাউম

আমি return new Promise(function(resolve, reject) { })একটি for...ofদৃশ্যে সন্ধান করেছি , যে একটি লুপের মধ্যে ব্যবহার করা এবং তারপরে লুপের মধ্যে কল resolve()করা pipe()পাইপ শেষ না হওয়া পর্যন্ত প্রোগ্রামের কার্যকারিতাটি বিরতি দেয় না, যেমনটি পছন্দসই, তবে ব্যবহারটি await new Promise(...)করে। পরেরটি কি বৈধ / সঠিক বাক্য গঠন? এটা 'শর্টহ্যান্ড' এর জন্য return await new Promise(...)? আপনি কি আমাকে বুঝতে সাহায্য করতে পারেন যে পরেরটি কেন কাজ করে এবং পূর্ববর্তীটি কেন কাজ করে না? প্রসঙ্গ জন্য, দৃশ্যকল্প হয় solution 02এর এই উত্তর
user1063287

14

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

টেইল কল অপ্টিমাইজেশন , বা "যথাযথ লেজ কল" , এমন একটি কৌশল যা দোভাষী তার কল স্ট্যাকটি অনুকূল করতে ব্যবহার করে। বর্তমানে, বেশিরভাগ রানটাইম এখনও এটিকে সমর্থন করে না - যদিও এটি প্রযুক্তিগতভাবে ES6 স্ট্যান্ডার্ডের অংশ - তবে ভবিষ্যতে এটির সমর্থন যোগ হতে পারে, সুতরাং আপনি ভাল কোডটি লিখে বর্তমানের জন্য প্রস্তুত করতে পারেন।

সংক্ষেপে, টিসিও (বা পিটিসি) সরাসরি কোনও ফাংশন দ্বারা ফিরে আসা কোনও ফাংশনের জন্য একটি নতুন ফ্রেম না খোলার মাধ্যমে কল স্ট্যাকটিকে অনুকূল করে । পরিবর্তে, এটি একই ফ্রেমটিকে পুনরায় ব্যবহার করে।

async function delay1Second() {
  return delay(1000);
}

যেহেতু delay()সরাসরি delay1Second()পাঠানো হয়েছে , পিটিসি সমর্থনকারী রানটাইমগুলি প্রথমে delay1Second()(বাইরের ফাংশন) জন্য একটি ফ্রেম খুলবে , তবে তারপরে (অভ্যন্তরীণ ফাংশন) জন্য অন্য ফ্রেমটি খোলার পরিবর্তে delay()এটি কেবল একই ফ্রেমটি পুনরায় ব্যবহার করবে যা বাইরের ফাংশনের জন্য খোলা হয়েছিল। এটি স্ট্যাকটিকে সর্বোত্তম করে তোলে কারণ এটি খুব বড় পুনরাবৃত্ত ক্রিয়াকলাপগুলির সাথে স্ট্যাকের ওভারফ্লো (hehe) প্রতিরোধ করতে পারে , যেমন fibonacci(5e+25),। মূলত এটি একটি লুপ হয়ে যায়, যা অনেক দ্রুত।

অভ্যন্তরীণ ফাংশনটি সরাসরি ফিরে আসলে পিটিসি সক্ষম হয় । ফাংশনটির ফলাফল ফিরে আসার আগে পরিবর্তিত হলে এটি ব্যবহার করা হয় না, উদাহরণস্বরূপ, যদি আপনার ছিল return (delay(1000) || null), বা return await delay(1000)

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

এই প্রশ্নে আরও পড়ুন: নোড.জেএস: অ্যাসিঙ্ক ফাংশনগুলিতে লেজ কলগুলির জন্য অপ্টিমাইজেশন রয়েছে?


3

এটি উত্তর দেওয়া একটি কঠিন প্রশ্ন, কারণ এটি আপনার ট্রান্সপ্লার (সম্ভবত babel) আসলে কীভাবে রেন্ডার করে তা অনুশীলনের উপর নির্ভর করে async/await। নির্বিশেষে পরিষ্কার যে জিনিস:

  • উভয় বাস্তবায়ন একই আচরণ করা উচিত, যদিও প্রথম প্রয়োগের চেইনে একটি কম থাকতে পারে Promise

  • বিশেষত আপনি অপ্রয়োজনীয় বাদ দিলে await, দ্বিতীয় সংস্করণটির জন্য ট্রান্সপোর্টার থেকে কোনও অতিরিক্ত কোডের প্রয়োজন হবে না, যখন প্রথমটি এটি করে।

একটি কোড পারফরম্যান্স এবং ডিবাগিং দৃষ্টিকোণ থেকে, দ্বিতীয় সংস্করণটি পছন্দনীয়, যদিও এটি খুব সামান্য তাই, প্রথম সংস্করণটির সামান্য স্বীকৃতি বেনিফিট রয়েছে, এতে এটি স্পষ্টভাবে ইঙ্গিত দেয় যে এটি কোনও প্রতিশ্রুতি ফেরায়।


ফাংশনগুলি একই আচরণ করবে কেন? প্রথমটি একটি সমাধান করা মান ( undefined) এবং দ্বিতীয়টি a প্রদান করে Promise
অমিত

4
@ উভয় ফাংশন একটি প্রতিশ্রুতি
ফেরান

অ্যাক। এই কারণেই আমি দাঁড়াতে পারছি না async/await- এটি যুক্তিযুক্ত হওয়া আমার পক্ষে আরও কঠিন। @ পিটাজে সঠিক, উভয় ফাংশন একটি প্রতিশ্রুতি দেয়।
nrabinowitz

আমি যদি উভয়ের সাথে উভয় অ্যাসিঙ্ক ফাংশনটির দেহকে ঘিরে রাখি তবে কী হবে try-catch? ইন return promiseকেস কোন rejection, ধরা হবে না সঠিক, যেহেতু, এ return await promiseক্ষেত্রে, এটা সঠিক হতে পারে হবে?
পিটাজে

উভয়ই প্রতিশ্রুতি দেয়, তবে প্রথম "প্রতিশ্রুতি দেয়" একটি আদিম মান, এবং দ্বিতীয়টি "প্রতিশ্রুতি" দেয় একটি প্রতিশ্রুতি। আপনি যদি awaitকোনও কোনও কল সাইটে এই প্রত্যেকে রাখেন, ফলাফলটি খুব আলাদা হবে।
অমিত

2

লক্ষণীয় পার্থক্য: প্রতিশ্রুতি প্রত্যাখ্যান বিভিন্ন জায়গায় পরিচালিত হয়

  • return somePromiseকল সাইটে কিছু প্রোমাইজ , এবং কল সাইটে স্থির করার জন্য কিছু প্রচার করবে (যদি থাকে তবে)। সুতরাং, যদি কিছুপ্রোমিজ প্রত্যাখ্যান করা হয় তবে এটি স্থানীয় ক্যাচ ব্লক দ্বারা পরিচালিত হবে না, তবে কল সাইটের ক্যাচ ব্লক।await

async function foo () {
  try {
    return Promise.reject();
  } catch (e) {
    console.log('IN');
  }
}

(async function main () {
  try {
    let a = await foo();
  } catch (e) {
    console.log('OUT');
  }
})();
// 'OUT'

  • return await somePromiseস্থানীয়ভাবে বসতি স্থাপনের জন্য প্রথমে কিছু অর্থের অপেক্ষায় থাকবে । অতএব, মান বা ব্যতিক্রম প্রথমে স্থানীয়ভাবে পরিচালিত হবে। => somePromiseপ্রত্যাখ্যাত হলে লোকাল ক্যাচ ব্লক কার্যকর করা হবে ।

async function foo () {
  try {
    return await Promise.reject();
  } catch (e) {
    console.log('IN');
  }
}

(async function main () {
  try {
    let a = await foo();
  } catch (e) {
    console.log('OUT');
  }
})();
// 'IN'

কারণ: return await Promiseস্থানীয়ভাবে এবং বাইরে উভয় ক্ষেত্রেই return Promiseঅপেক্ষা করা হয়, কেবলমাত্র বাইরে অপেক্ষা করা

বিস্তারিত পদক্ষেপ:

প্রতিশ্রুতি ফিরে

async function delay1Second() {
  return delay(1000);
}
  1. কল delay1Second();
const result = await delay1Second();
  1. ভিতরে delay1Second(), ফাংশন delay(1000)সঙ্গে সঙ্গে একটি প্রতিশ্রুতি ফেরত [[PromiseStatus]]: 'pending। এটি কল করুন delayPromise
async function delay1Second() {
  return delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
}
  1. অ্যাসিঙ্ক ফাংশনগুলি তাদের রিটার্ন মানটি Promise.resolve()( উত্স ) ভিতরে গুটিয়ে রাখবে । কারণ delay1Secondএকটি অ্যাসিঙ্ক ফাংশন, আমাদের রয়েছে:
const result = await Promise.resolve(delayPromise); 
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
  1. Promise.resolve(delayPromise)delayPromiseকিছুই না করে ফিরে আসে কারণ ইনপুটটি ইতিমধ্যে একটি প্রতিশ্রুতি ( এমডিএন প্রতিশ্রুতি দেখুন olve সমাধান করুন ):
const result = await delayPromise; 
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
  1. awaitdelayPromiseস্থির হওয়া অবধি অপেক্ষা করুন ।
  • যদি delayPromiseপ্রতিশ্রুতি = 1 দিয়ে পূর্ণ হয়:
const result = 1; 
  • ELSE delayPromiseপ্রত্যাখ্যান করা হয়:
// jump to catch block if there is any

প্রতিশ্রুতি প্রত্যাবর্তন

async function delay1Second() {
  return await delay(1000);
}
  1. কল delay1Second();
const result = await delay1Second();
  1. ভিতরে delay1Second(), ফাংশন delay(1000)সঙ্গে সঙ্গে একটি প্রতিশ্রুতি ফেরত [[PromiseStatus]]: 'pending। এটি কল করুন delayPromise
async function delay1Second() {
  return await delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
}
  1. স্থানীয় প্রতীক্ষা স্থির না হওয়া পর্যন্ত অপেক্ষা করবে delayPromise
  • কেস 1 : delayPromiseপ্রতিশ্রুতি 1:
async function delay1Second() {
  return 1;
}
const result = await Promise.resolve(1); // let's call it "newPromise"
const result = await newPromise; 
// newPromise.[[PromiseStatus]]: 'resolved'
// newPromise.[[PromiseValue]]: 1
const result = 1; 
  • কেস 2 : delayPromiseপ্রত্যাখ্যান করা হয়েছে:
// jump to catch block inside `delay1Second` if there is any
// let's say a value -1 is returned in the end
const result = await Promise.resolve(-1); // call it newPromise
const result = await newPromise;
// newPromise.[[PromiseStatus]]: 'resolved'
// newPromise.[[PromiseValue]]: -1
const result = -1;

শব্দকোষ:

  • এগুতেই: Promise.[[PromiseStatus]]থেকে পরিবর্তন pendingকরতে resolvedবাrejected

0

এখানে আমি কিছু কোড ব্যবহারিক রেখেছি যাতে আপনি এটির পার্থক্যটিকে কমিয়ে আনতে পারেন

 let x = async function () {
  return new Promise((res, rej) => {
    setTimeout(async function () {
      console.log("finished 1");
      return await new Promise((resolve, reject) => { // delete the return and you will see the difference
        setTimeout(function () {
          resolve("woo2");
          console.log("finished 2");
        }, 5000);
      });
      res("woo1");
    }, 3000);
  });
};

(async function () {
  var counter = 0;
  const a = setInterval(function () { // counter for every second, this is just to see the precision and understand the code
    if (counter == 7) {
      clearInterval(a);
    }

    console.log(counter);
    counter = counter + 1;
  }, 1000);
  console.time("time1");
  console.log("hello i starting first of all");
  await x();
  console.log("more code...");
  console.timeEnd("time1");
})();

"এক্স" ফাংশনটি হ'ল একটি ফাংশন অ্যাসিঙ্কের তুলনায় এটি অন্যান্য ফুকন যদি এটি মুছে ফেলবে তবে এটি "আরও কোড ..." মুদ্রণ করবে

ভেরিয়েবল এক্সটি কেবল একটি অ্যাসিনক্রোনাস ফাংশন যার পরিবর্তে অন্য একটি অ্যাসিনক্রোনাস ফাংশন থাকে, কোডের মূল অংশে আমরা ভেরিয়েবল এক্স এর ফাংশনটি কল করার জন্য অপেক্ষা করি, যখন এটি সম্পূর্ণ হয় এটি কোডের ক্রম অনুসরণ করে, তবে এটি স্বাভাবিক হবে "অ্যাসিঙ্ক / অপেক্ষার" জন্য, তবে এক্স ফাংশনের ভিতরে আরও একটি অ্যাসিনক্রোনাস ফাংশন রয়েছে এবং এটি একটি প্রতিশ্রুতি দেয় বা একটি "প্রতিশ্রুতি" দেয় যা মূল কোডটি ভুলে গিয়ে এক্স ফাংশনের অভ্যন্তরে থাকবে, অর্থাৎ এটি প্রিন্ট করবে না "কনসোল.লগ (" আরও কোড .. "), অন্যদিকে, আমরা যদি" ​​অপেক্ষা "রাখি তবে এটি প্রতিটি ক্রিয়াকলাপের জন্য অপেক্ষা করবে যা শেষ হয় এবং শেষ পর্যন্ত মূল কোডটির স্বাভাবিক ক্রম অনুসরণ করে।

"কনসোল.লগের নীচে (" সমাপ্ত 1 "" রিটার্ন "মুছুন, আপনি আচরণটি দেখতে পাবেন।


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

0

এখানে একটি টাইপ স্ক্রিপ্ট উদাহরণ রয়েছে যা আপনি দৌড়াতে পারেন এবং নিজেকে বোঝাতে পারেন যে আপনার "প্রত্যাবর্তনের অপেক্ষায়" দরকার

async function  test() {
    try {
        return await throwErr();  // this is correct
        // return  throwErr();  // this will prevent inner catch to ever to be reached
    }
    catch (err) {
        console.log("inner catch is reached")
        return
    }
}

const throwErr = async  () => {
    throw("Fake error")
}


void test().then(() => {
    console.log("done")
}).catch(e => {
    console.log("outer catch is reached")
});

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