۲۹ شهریور ۱۴۰۳

Techboy

اخبار و اطلاعات روز تکنولوژی

پاسخ‌های تماس جاوا اسکریپت، وعده‌ها و همگام‌سازی/انتظار توضیح داده شده است

پاسخ به تماس ها برای مدیریت کدهای ناهمزمان در جاوا اسکریپت خوب عمل می کند، اما وعده ها و کلمات کلیدی همگام و انتظار پاک تر و انعطاف پذیرتر هستند.

پاسخ به تماس ها برای مدیریت کدهای ناهمزمان در جاوا اسکریپت خوب عمل می کند، اما وعده ها و کلمات کلیدی همگام و انتظار پاک تر و انعطاف پذیرتر هستند.

برخورد با کد ناهمزمان – به معنای هر نوع کدی که بلافاصله اجرا نمی شود – می تواند مشکل باشد. رفتار ناهمزمان یکی از منابع اصلی پیچیدگی در هر محیط نرم افزاری است. نشان دهنده وقفه ای در جریان اجراست که ممکن است به هر تعداد نتیجه منجر شود. این مقاله سه راه برای مدیریت رفتار ناهمزمان در جاوا اسکریپت را معرفی می کند. ما با نگاهی به تماس‌ها شروع می‌کنیم، سپس وعده‌ها و کلیدواژه‌های async و await را به‌عنوان جایگزین‌های مدرن‌تر معرفی می‌کنم.

کد ناهمزمان چیست؟

کد ناهمزمان (کد ناهمگام) می‌گوید: برو در حالی که کارهای دیگر را انجام می‌دهم، کاری انجام بده، سپس وقتی نتایج آماده شد به من اطلاع بده که چه اتفاقی افتاده است. همچنین به عنوان همزمان شناخته می شود، async در انواع موارد استفاده مهم است، اما به ویژه در هنگام تعامل با سیستم های خارجی و شبکه حیاتی است. در مرورگر، برقراری تماس‌های API از راه دور یک مورد استفاده همه‌جا برای کدهای ناهمزمان است، اما تعداد بی‌شماری دیگر هم در جلو و هم در پشتی وجود دارد.

بازخوانی در جاوا اسکریپت

تا سال ۲۰۱۶، تا زمانی که Promise شیء به زبان معرفی شد. با این حال، توسعه دهندگان جاوا اسکریپت عملکردهای مشابهی را اجرا کرده بودند در سالهای خودشان قبل از رسیدن وعده ها به صحنه.

بیایید به برخی از تفاوت‌های بین تماس‌های برگشتی و وعده‌ها نگاهی بیندازیم و ببینیم چگونه می‌توانیم از هر تکنیک برای هماهنگ کردن چندین لایه اجرا استفاده کنیم.

یک مثال کلاسیک پاسخ به تماس

توابع ناهمزمان که از تماس‌های برگشتی استفاده می‌کنند، تابعی را به عنوان پارامتر می‌گیرند، که پس از تکمیل کار فراخوانی می‌شود. اگر تا به حال از چیزی مانند setTimeout در مرورگر استفاده کرده‌اید، از تماس‌های برگشتی استفاده کرده‌اید.


// You can define your callback separately...
let myCallback = () => {
  console.log('Called!');
};
setTimeout(myCallback, 3000);
// … but it’s also common to see callbacks defined inline
setTimeout(() => {
  console.log('Called!');
}, ۳۰۰۰);
console.log(“This happens first!”);

لیست ۱ به دو روش مختلف می گوید: بعد از ۳۰۰۰ میلی ثانیه، “Callid!” به کنسول. در هر دو مورد، خط “اول اتفاق می افتد!” ابتدا خروجی خواهد گرفت. دلیل آن این است که این تماس‌های ناهمزمان هستند و جریان اجرای کد تا زمانی که زمان‌بندی‌ها در انتظار وقوع هستند ادامه می‌یابد. این ماهیت برنامه نویسی ناهمزمان است.

AWS Amplify ابزار توسعه بصری را اضافه می کند

تماس‌های تودرتو و هرم عذاب

تکلیف‌های تماس برای مدیریت کدهای ناهمزمان به خوبی کار می‌کنند، اما زمانی که شما شروع به هماهنگی چندین عملکرد ناهمزمان می‌کنید، دشوار می‌شوند. به عنوان مثال، اگر بخواهیم دو ثانیه صبر کنیم و چیزی را ثبت کنیم، سپس سه ثانیه صبر کنیم و چیز دیگری را ثبت کنیم، سپس چهار ثانیه صبر کنیم و چیز دیگری را ثبت کنیم، نحو ما به سرعت عمیقاً تو در تو می شود. این حالتی است که گاهی اوقات به عنوان جهنم پاسخ به تماس شناخته می‌شود.


setTimeout(() => {
  console.log('First Callback!');
  setTimeout(() => {
    console.log('Second Callback!');
    setTimeout(() => {
      console.log('Third Callback!');
    }, ۴۰۰۰);
  }, ۳۰۰۰);
}, ۲۰۰۰);

فهرست ۲ نگاهی اجمالی به تماس های زشت ارائه می دهد. هرچه کد بیشتری را در تماس های تودرتو قرار دهیم، تشخیص اینکه چه اتفاقی می افتد و هر تماس کجا تکمیل می شود دشوارتر است. این ممکن است یک مثال بی اهمیت به نظر برسد (و همینطور است)، اما ایجاد چندین درخواست وب پشت سر هم بر اساس نتایج بازگشت درخواست قبلی غیر معمول نیست.

مشکل “بازگشت های تودرتو” همیشه ظاهر می شود. در لیست ۳، ما یک مثال درگیرتر را در یک محیط Node.js می بینیم که در آن با چندین فایل سروکار داریم.


fs.readdir('/path/to/dir', function (err, files) {
  if (err) {
    console.log(err);
    return;
  }
  
  files.forEach(function (file) {
    fs.readFile('/path/to/dir/' + file, 'utf8', function (err, contents) {
      if (err) {
        console.log(err);
        return;
      }
      // do something with the file
      
      fs.writeFile('/path/to/new/dir/' + file, contents, function (err) {
        if (err) {
          console.log(err);
          return;
        }
        // do something with the file
      });
    });
  });
});

پیروی از این کد در حال حاضر دشوار است، حتی اگر کار خیلی پیچیده ای انجام نمی دهد و هیچ یک از منطق تجاری واقعی وجود ندارد. فهمیدن اینکه کجا هستید و دسته‌های فایلی که در چه زمانی باز هستند دشوار است. ما فقط از طریق هر فایل در یک دایرکتوری حلقه می زنیم و محتویات را می خوانیم و از آن در یک فایل جدید در یک دایرکتوری دیگر استفاده می کنیم.

نحوه پیاده سازی احراز هویت در حداقل API ها در ASP.NET Core

بنابراین، اکنون محدودیت های تماس های برگشتی را مشاهده کرده اید. آنها برای استفاده های ساده مناسب هستند اما در موقعیت های پیچیده تر عالی نیستند. خوشبختانه، جاوا اسکریپت مدرن شی Promise و کلیدواژه های async و await را به عنوان راه حل های انعطاف پذیرتر به ما می دهد.

قول ها

Promises نیاز دارد که تابع به گونه‌ای نوشته شود که یک شی Promise را برگرداند، که دارای ویژگی‌های استاندارد برای مدیریت رفتار بعدی و هماهنگی چند وعده است.

می‌توانیم یک تماس مهلت زمانی را در یک Promise ببندیم تا ببینیم کارها چگونه کار می‌کنند. می‌توانید نمونه‌هایی از مهلت زمانی را در برخی از آگهی‌های NPM ببینید و درباره آنها بیشتر بدانید اینجا. فهرست ۴ یک مهلت زمانی مبتنی بر وعده به نام انتظار ارائه می دهد.


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

در فهرست ۴، نگاهی اجمالی به نحوه استفاده کد سرویس از Promise برای مقابله با شرایط ناهمزمان می‌بینیم. در اصل، تابع wait ما یک شی Promise را برمی گرداند، که آرگومان resolve ارسال شده به سازنده Promise را فراخوانی می کند. (اتفاقاً، resolve نمونه‌ای از یک تابع مرتبه بالاتر است.) ممکن است کد در ابتدا پیچیده به نظر برسد، اما ایده ساده است: هنگامی که کد به Promise منتقل می‌شود. سازنده تابع resolve را فراخوانی می‌کند، به کد کلاینت هشدار داده می‌شود که Promise تکمیل شده است. توجه داشته باشید که نام resolve ضروری نیست. هر آرگومانی است که به تابع ارسال شده به Promise ارسال می شود. پشتیبانی مشابهی برای شرایط خطا وجود دارد.

بعد، در فهرست ۵، می‌توانید تابع wait را مشاهده کنید که با تابع سپس استفاده می‌شود.


wait(3000).then(() => {
  console.log('Called after 3 seconds');
});

ایده اصلی این است که اکنون می‌توانیم wait را فراخوانی کنیم و آرگومان مربوطه را ارسال کنیم (زمان انتظار) و مجبور نباشیم در کنترل‌کننده پاسخ به تماس به‌عنوان یک رمز عبور ارسال کنیم. بحث و جدل. در عوض، کنترل کننده در فراخوانی .then() داده می شود. این امر امکان زنجیره‌سازی چندین تماس را با هم باز می‌کند، همانطور که در فهرست ۶ مشاهده می‌کنیم.


wait(2000)
  .then(() => {
    console.log('First Callback!');
    return wait(3000);
  })
  .then(() => {
    console.log('Second Callback!');
    return wait(4000);
  })
  .then(() => {
    console.log('Third Callback!');
    return wait(4000);
  });

همچنین می‌توانیم با استفاده از تابع ثابت Promise.all()، همانطور که در فهرست ۷ نشان داده شده است، تماس‌ها را با هم جمع کنیم.


Promise.all([
  wait(2000),
  wait(3000),
  wait(4000)
]).then(() => console.log('Everything is done!'));

Promise همچنین دارای یک روش .race() است که به محض رفع یا خطا شدن هر یک از وعده‌ها برمی‌گردد.

VirtualBox 7 از راه دور به Oracle Cloud منتقل می شود

بررسی خطا با وعده‌ها

اگر Promise خطایی را برمی‌گرداند، می‌توان آن را با .catch مدیریت کرد. هنگامی که Promise ایجاد می شود، آرگومان دوم به همراه resolve دریافت می کند که معمولاً error یا err نام دارد. هنگام فراخوانی، این آرگومان خطا باعث می‌شود که کد مشتری متد catch() را اجرا کند.

جاوااسکریپت ناهمگام/انتظار

به عنوان مثال نهایی، فهرست ۸ نحوه استفاده از تابع wait() را با کلیدواژه‌های async و await نشان می‌دهد.

>


async function foo() {
  await wait(3000);
  console.log('Called after 3 seconds');
}

foo();

فهرست ۸ یک تابع ناهمزمان، foo() را با کلمه کلیدی async ایجاد می کند. این کلمه کلیدی به مترجم می گوید که یک کلمه کلیدی wait در داخل وجود خواهد داشت. این کلمه کلیدی اجازه می دهد تا یک تابع ناهمزمان مانند wait() را به گونه ای اجرا کند که گویی همزمان است. کد در اینجا مکث می‌کند تا wait(3000) کامل شود و سپس ادامه می‌دهد.

عملکردهای انتظار قابلیت بیشتری دارند، از جمله مدیریت نتایج. برای اطلاعات بیشتر درباره این کلمات کلیدی به نحوه استفاده از async و انتظار در جاوا اسکریپت مراجعه کنید.