از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
تبدیل Callbacks به Promises در Node.js چند سال پیش، callbacks تنها راهی بود که میتوانستیم به اجرای کد ناهمزمان در جاوا اسکریپت برسیم. مشکلات کمی در ارتباط با تماس وجود داشت و قابل توجه ترین آنها “جهنم پاسخ به تماس” بود. با ES6، Promises به عنوان راه حلی برای آن مشکلات معرفی شد. و در نهایت، کلمات کلیدی async/wait…
سرفصلهای مطلب
معرفی
چند سال پیش، پاسخ به تماس تنها راهی بود که میتوانستیم به اجرای کد ناهمزمان در جاوا اسکریپت برسیم. مشکلات کمی در تماسهای تلفنی وجود داشت و قابلتوجهترین آنها «جهنم پاسخ به تماس» بود.
با ES6، وعده ها به عنوان راه حلی برای آن مشکلات معرفی شدند. و در نهایت، async/await
کلمات کلیدی برای تجربه لذت بخش تر و خوانایی بهتر معرفی شدند.
حتی با افزودن رویکردهای جدید، هنوز ماژولها و کتابخانههای بومی زیادی وجود دارند که از callback استفاده میکنند. در این مقاله قصد داریم در مورد روش تبدیل callback های جاوا اسکریپت به Promises صحبت کنیم. دانش ES6 مفید خواهد بود زیرا ما از ویژگی هایی مانند اپراتورهای گسترش برای آسان کردن کارها استفاده خواهیم کرد.
Callback چیست
بازخوانی یک آرگومان تابعی است که اتفاقاً خود یک تابع است. در حالی که میتوانیم هر تابعی را برای پذیرش تابع دیگری ایجاد کنیم، تماسهای برگشتی عمدتاً در عملیات ناهمزمان استفاده میشوند.
جاوا اسکریپت یک زبان تفسیری است که فقط می تواند process یک خط کد در یک زمان انجام برخی از کارها ممکن است مدت زیادی طول بکشد، مانند دانلود یا خواندن یک فایل بزرگ. جاوا اسکریپت این وظایف طولانی مدت را به روشی متفاوت بارگذاری می کند process در مرورگر یا محیط Node.js. به این ترتیب، اجرای همه کدهای دیگر را مسدود نمی کند.
معمولاً توابع ناهمزمان تابع فراخوانی را می پذیرند، به طوری که وقتی کامل شدند، می توانیم process داده های آنها
بیایید مثالی بزنیم، ما یک تابع callback می نویسیم که زمانی اجرا می شود که برنامه با موفقیت یک فایل را از هارد دیسک ما بخواند.
برای این منظور از یک فایل متنی به نام استفاده می کنیم sample.txt
، حاوی موارد زیر است:
Hello world from sample.txt
سپس یک اسکریپت ساده Node.js برای خواندن فایل بنویسیم:
const fs = require('fs');
fs.readFile('./sample.txt', 'utf-8', (err, data) => {
if (err) {
// Handle error
console.error(err);
return;
}
// Data is string do something with it
console.log(data);
});
for (let i = 0; i < 10; i++) {
console.log(i);
}
اجرای این کد باید نتیجه دهد:
0
...
8
9
Hello world from sample.txt
اگر این کد را اجرا کنید، باید ببینید 0..9
قبل از اجرای فراخوان چاپ می شود. این به دلیل مدیریت ناهمزمان جاوا اسکریپت است که قبلاً در مورد آن صحبت کردیم. تماس برگشتی که محتویات فایل را ثبت می کند، تنها پس از خواندن فایل فراخوانی می شود.
به عنوان یک نکته، می توان از callback در روش های همزمان نیز استفاده کرد. مثلا، Array.sort()
یک تابع پاسخ به تماس را می پذیرد که به شما امکان می دهد روش مرتب سازی عناصر را سفارشی کنید.
توابعی که پاسخ تماس را می پذیرند نامیده می شوند توابع مرتبه بالاتر.
اکنون ما ایده بهتری در مورد تماس های برگشتی داریم. بیا حرکت کنیم روی و ببین وعده چیست
قول چیست
وعده ها با معرفی شدند ECMAScript 2015 (معمولاً به عنوان ES6) برای بهبود تجربه توسعه دهنده با برنامه نویسی ناهمزمان. همانطور که از نامش پیداست، یک است وعده که یک شی جاوا اسکریپت در نهایت a را برمی گرداند ارزش یا یک خطا.
یک قول دارای 3 حالت است:
- انتظار: حالت اولیه که نشان می دهد عملیات ناهمزمان کامل نشده است.
- برآورده شد: به این معنی که عملیات ناهمزمان با موفقیت انجام شد.
- رد شد: به این معنی که عملیات ناهمزمان با شکست مواجه شد.
اکثر وعده ها به این شکل ختم می شوند:
someAsynchronousFunction()
.then(data => {
// After promise is fulfilled
console.log(data);
})
.catch(err => {
// If promise is rejected
console.error(err);
});
وعده ها در جاوا اسکریپت مدرن مهم هستند زیرا با آن استفاده می شوند async/await
کلمات کلیدی که در ECMAScript 2016. با async/await
، نیازی به استفاده از callback یا then()
و catch()
برای نوشتن کد ناهمزمان
اگر قرار بود مثال قبلی اقتباس شود، به این صورت خواهد بود:
try {
const data = await someAsynchronousFunction();
} catch(err) {
// If promise is rejected
console.error(err);
}
این بسیار شبیه جاوا اسکریپت همگام “عادی” است! می توانید در مورد آن بیشتر بدانید async/await
در مقاله ما، Node.js Async Await در ES7.
اکثر کتابخانههای محبوب جاوا اسکریپت و پروژههای جدید از Promises استفاده میکنند async/await
کلید واژه ها.
با این حال، اگر یک مخزن موجود را بهروزرسانی میکنید یا با یک پایگاه کد قدیمی مواجه میشوید، احتمالاً علاقهمند هستید که APIهای مبتنی بر تماس را به APIهای مبتنی بر Promise منتقل کنید تا تجربه توسعه خود را بهبود ببخشید. تیم شما نیز سپاسگزار خواهد بود.
بیایید به چند روش برای تبدیل تماس های برگشتی به وعده ها نگاه کنیم!
تبدیل پاسخ به تماس به قول
Node.js Promisify
اکثر توابع ناهمزمان که در Node.js پاسخ تماس را می پذیرند، مانند the fs
ماژول (سیستم فایل)، دارای یک سبک استاندارد پیاده سازی است – فراخوانی به عنوان آخرین پارامتر ارسال می شود.
به عنوان مثال در اینجا روش خواندن یک فایل با استفاده از آن آورده شده است fs.readFile()
بدون تعیین کدگذاری متن:
fs.readFile('./sample.txt', (err, data) => {
if (err) {
console.error(err);
return;
}
// Data is a buffer
console.log(data);
});
توجه داشته باشید: اگر مشخص کنید utf-8
به عنوان رمزگذاری شما یک خروجی رشته دریافت خواهید کرد. اگر رمزگذاری را مشخص نکنید، a دریافت خواهید کرد Buffer
خروجی
علاوه بر این، فراخوانی که به تابع ارسال می شود، باید یک را بپذیرد Error
همانطور که اولین پارامتر است. پس از آن، هر تعداد خروجی می تواند وجود داشته باشد.
اگر تابعی که باید در یک Promise مخفی کنید از آن قوانین پیروی می کند، می توانید از آن استفاده کنید استفاده کردن.وعده دادن، یک ماژول بومی Node.js که تماس های مربوط به Promises را مخفی می کند.
برای انجام این کار، ابتدا import را util
مدول:
const util = require('util');
سپس شما استفاده کنید promisify
روش پنهان کردن آن به قول:
const fs = require('fs');
const readFile = util.promisify(fs.readFile);
اکنون از تابع جدید ایجاد شده به عنوان یک وعده معمولی استفاده کنید:
readFile('./sample.txt', 'utf-8')
.then(data => {
console.log(data);
})
.catch(err => {
console.log(err);
});
به طور متناوب، می توانید از async/await
کلمات کلیدی همانطور که در مثال زیر آورده شده است:
const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
(async () => {
try {
const content = await readFile('./sample.txt', 'utf-8');
console.log(content);
} catch (err) {
console.error(err);
}
})();
شما فقط می توانید استفاده کنید await
کلمه کلیدی داخل تابعی که با آن ایجاد شده است async
، از این رو چرا در این مثال یک تابع پوشش داریم. این پوشش تابع به عنوان عبارات تابع بلافاصله فراخوانی شده نیز شناخته می شود.
اگر پاسخ تماس شما از آن استاندارد خاص پیروی نمی کند، نگران نباشید. این util.promisify()
تابع می تواند به شما اجازه دهد شخصی سازی چگونه تبدیل اتفاق می افتد
توجه داشته باشید: وعده ها خیلی زود پس از معرفی رایج شدند. Node.js در حال حاضر اکثر، اگر نه همه، توابع اصلی خود را از یک callback به یک API مبتنی بر Promise تبدیل کرده است.
اگر نیاز به کار با فایلها با استفاده از Promises دارید، از آن استفاده کنید کتابخانه ای که با Node.js ارائه می شود.
تاکنون یاد گرفتهاید که چگونه میتوانید تماسهای استاندارد Node.js را به وعدهها پنهان کنید. این ماژول فقط موجود است روی Node.js از نسخه 8 به بعد. اگر در مرورگر یا نسخه قبلی Node کار می کنید، احتمالاً بهتر است نسخه مبتنی بر قول خود را از تابع ایجاد کنید.
ایجاد وعده شما
بیایید در مورد چگونگی تماس های مخفیانه به قول ها صحبت کنیم util.promisify()
عملکرد در دسترس نیست
ایده ایجاد یک جدید است Promise
شیئی که اطراف تابع callback می پیچد. اگر تابع callback خطایی را برگرداند، Promise را با خطا رد می کنیم. اگر تابع callback خروجی بدون خطا برگرداند، Promise را با خروجی حل می کنیم.
بیایید با تبدیل یک callback به یک تابع برای تابعی که تعداد ثابتی از پارامترها را می پذیرد، شروع کنیم:
const fs = require('fs');
const readFile = (fileName, encoding) => {
return new Promise((resolve, reject) => {
fs.readFile(fileName, encoding, (err, data) => {
if (err) {
return reject(err);
}
resolve(data);
});
});
}
readFile('./sample.txt')
.then(data => {
console.log(data);
})
.catch(err => {
console.log(err);
});
عملکرد جدید ما readFile()
دو آرگومان را میپذیرد که ما از آنها برای خواندن فایلها استفاده میکردیم fs.readFile()
. سپس یک جدید ایجاد می کنیم Promise
شیئی که روی تابع میپیچد که در این مورد، پاسخ تماس را میپذیرد fs.readFile()
.
به جای بازگرداندن یک خطا، ما reject
وعده. به جای ثبت اطلاعات فوری، ما resolve
وعده. سپس از Promise-based استفاده می کنیم readFile()
مانند قبل عمل کند
بیایید تابع دیگری را امتحان کنیم که تعدادی پارامتر پویا را می پذیرد:
const getMaxCustom = (callback, ...args) => {
let max = -Infinity;
for (let i of args) {
if (i > max) {
max = i;
}
}
callback(max);
}
getMaxCustom((max) => { console.log('Max is ' + max) }, 10, 2, 23, 1, 111, 20);
پارامتر callback نیز اولین پارامتر است که با توابعی که پاسخ تماس را می پذیرند کمی غیرعادی می شود.
تبدیل به قول به همین صورت انجام می شود. ما یک جدید ایجاد می کنیم Promise
شیئی که در اطراف تابع ما قرار می گیرد که از یک تماس برگشتی استفاده می کند. سپس ما reject
اگر با خطا مواجه شدیم و resolve
وقتی نتیجه را داریم
نسخه وعده داده شده ما به این صورت است:
const getMaxPromise = (...args) => {
return new Promise((resolve) => {
getMaxCustom((max) => {
resolve(max);
}, ...args);
});
}
getMaxCustom(10, 2, 23, 1, 111, 20)
.then(max => console.log(max));
هنگام ایجاد وعده ما، فرقی نمیکند که تابع به صورت غیراستاندارد یا با آرگومانهای زیاد از تماسهای برگشتی استفاده کند. ما کنترل کاملی بر روش انجام آن داریم و اصول یکسان است.
نتیجه
در حالی که callbacks راه پیشفرض استفاده از کد ناهمزمان در جاوا اسکریپت بوده است، Promises روش مدرنتری است که توسعهدهندگان معتقدند استفاده از آن آسانتر است. اگر زمانی با یک پایگاه کد مواجه شدیم که از تماسهای برگشتی استفاده میکند، اکنون میتوانیم آن تابع را Promise کنیم.
در این مقاله برای اولین بار روش استفاده را مشاهده کردید utils.promisfy()
روشی در Node.js برای تبدیل توابعی که پاسخ تماس را می پذیرند به Promises. سپس دیدید که چگونه خودتان را بسازید Promise
شیئی که در اطراف تابعی قرار می گیرد که پاسخ تماس را بدون استفاده از کتابخانه های خارجی می پذیرد.
با این کار، بسیاری از کدهای جاوا اسکریپت قدیمی می توانند به راحتی با پایگاه های کد و شیوه های مدرن تر ترکیب شوند! مثل همیشه کد منبع موجود است روی GitHub.
(برچسبها برای ترجمه)# جاوا اسکریپت
منتشر شده در 1403-01-21 08:18:03