از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
Node.js Async Await در ES7 یکی از هیجان انگیزترین ویژگی های جاوا اسکریپت (و بنابراین Node.js) دستور async/wait است که در ES7 معرفی شده است. اگرچه اساساً فقط قند نحوی است روی در بالای Promises، این دو کلمه کلیدی به تنهایی باید نوشتن کدهای ناهمزمان در Node را بسیار قابل تحملتر کنند. همه چیز را حذف می کند …
سرفصلهای مطلب
یکی از هیجان انگیزترین ویژگی های جاوا اسکریپت (و بنابراین Node.js) این است async
/await
نحو در حال معرفی ES7. اگرچه اساساً فقط قند نحوی است روی در بالای Promises، این دو کلمه کلیدی به تنهایی باید نوشتن کدهای ناهمزمان در Node را بسیار قابل تحملتر کنند. همه اینها مشکل جهنم برگشت تماس را از بین می برد و حتی به ما اجازه می دهد از ساختارهای کنترل جریان در اطراف کد ناهمزمان خود استفاده کنیم.
در طول این مقاله نگاهی خواهیم داشت به اینکه Promises چه مشکلی دارد و چگونه جدید است await
ویژگی می تواند کمک کند، و چگونه می توانید شروع به استفاده از آن کنید همین الان.
مشکل با وعده ها
مفهوم “وعده” در جاوا اسکریپت مدتی است که وجود داشته است و سال هاست که به لطف کتابخانه های شخص ثالث قابل استفاده است. پرنده ابی و qبدون ذکر پشتیبانی بومی اخیراً اضافه شده در ES6.
آنها یک راه حل عالی برای مشکل جهنم تماس مجدد بوده اند، اما متأسفانه آنها همه مشکلات ناهمزمان را حل نمی کنند. در حالی که Promises یک پیشرفت عالی است، ما را مجبور به سادهسازی بیشتر میکند.
فرض کنید می خواهید از REST API GitHub برای یافتن تعداد ستاره های یک پروژه استفاده کنید. در این مورد، احتمالاً از عالی استفاده خواهید کرد درخواست – قول کتابخانه با استفاده از رویکرد مبتنی بر قول، شما باید درخواست را ارسال کنید و نتیجه را در پاسخی که به آن ارسال می کنید، برگردانید. .then()
، مثل این:
var request = require('request-promise');
var options = {
url: 'https://api.github.com/repos/scottwrobinson/camo',
headers: {
'User-Agent': 'YOUR-GITHUB-USERNAME'
}
};
request.get(options).then(function(body) {
var json = JSON.parse(body);
console.log('Camo has', json.stargazers_count, 'stars!');
});
این اراده print چیزی شبیه به:
$ node index.js
Camo has 1,000,000 stars!
خوب، شاید این عدد کمی اغراق آمیز باشد، اما شما متوجه موضوع شدید 😉
انجام فقط یک درخواست مانند این با Promises خیلی سخت نیست، اما اگر بخواهیم همان درخواست را برای بسیاری از مخازن مختلف داشته باشیم چه میشود. روی گیت هاب؟ و اگر ما نیاز به اضافه کردن جریان کنترل (مانند شرطی یا حلقه) در اطراف درخواست ها داشته باشیم، چه اتفاقی می افتد؟ همانطور که نیازهای شما پیچیده تر می شود، کار با Promises سخت تر می شود و همچنان کد شما را پیچیده می کند. آنها هنوز هم بهتر از تماس های معمولی هستند زیرا شما تودرتوی نامحدود ندارید، اما همه مشکلات شما را حل نمی کنند.
برای سناریوهای پیچیدهتر مانند آنچه در کد زیر است، باید در زنجیرهبندی Promises با یکدیگر و درک آن مهارت داشته باشید. کی و کجا کد ناهمزمان شما اجرا می شود.
"use strict";
var request = require('request-promise');
var headers = {
'User-Agent': 'YOUR-GITHUB-USERNAME'
};
var repos = (
'scottwrobinson/camo',
'facebook/react',
'scottwrobinson/twentyjs',
'moment/moment',
'nodejs/node',
'lodash/lodash'
);
var issueTitles = ();
var reqs = Promise.resolve();
repos.forEach(function(r) {
var options = { url: 'https://api.github.com/repos/' + r, headers: headers };
reqs = reqs.then(function() {
return request.get(options);
}).then(function(body) {
var json = JSON.parse(body);
var p = Promise.resolve();
// Only make request if it has open issues
if (json.has_issues) {
var issuesOptions = { url: 'https://api.github.com/repos/' + r + '/issues', headers: headers };
p = request.get(issuesOptions).then(function(ibody) {
var issuesJson = JSON.parse(ibody);
if (issuesJson(0)) {
issueTitles.push(issuesJson(0).title);
}
});
}
return p;
});
});
reqs.then(function() {
console.log('Issue titles:');
issueTitles.forEach(function(t) {
console.log
});
});
توجه داشته باشید: GitHub به شدت درخواستهای احراز هویت نشده را محدود میکند، بنابراین تعجب نکنید اگر پس از اجرای کد بالا فقط چند بار از آن استفاده کنید. شما می توانید این محدودیت را افزایش دهید ارسال شناسه / راز مشتری.
در زمان نوشتن این کد، اجرای این کد موارد زیر را به همراه خواهد داشت:
$ node index.js
Issue titles:
feature request: bulk create/save support
Made renderIntoDocument tests asynchronous.
moment issue template
test: robust handling of env for npm-test-install
فقط با اضافه کردن a for
حلقه و یک if
عبارت کد ناهمزمان ما خواندن و درک آن را بسیار دشوارتر می کند. این نوع پیچیدگی را فقط میتوان برای مدت طولانی ادامه داد، قبل از اینکه کار با آن خیلی سخت شود.
با نگاهی به کد، می توانید بلافاصله به من بگویید که درخواست ها واقعاً کجا اجرا می شوند یا هر بلوک کد به چه ترتیبی اجرا می شود؟ احتمالاً بدون مطالعه دقیق آن نه.
ساده سازی با Async/Await
جدید async
/await
سینتکس به شما امکان می دهد همچنان از Promises استفاده کنید، اما نیاز به ارائه یک تماس به زنجیره زنجیره ای را از بین می برد. then()
مواد و روش ها. مقداری که باید به then()
در عوض تماس برگشتی مستقیماً از تابع ناهمزمان برگردانده میشود، درست مثل اینکه یک تابع مسدودکننده همزمان باشد.
let value = await myPromisifiedFunction();
در حالی که به ظاهر ساده است، این یک ساده سازی بزرگ برای طراحی کد جاوا اسکریپت ناهمزمان است. تنها نحو اضافی مورد نیاز برای رسیدن به این است await
کلمه کلیدی. بنابراین اگر میدانید Promises چگونه کار میکند، درک روش استفاده از این کلمات کلیدی جدید از زمان ساخت آنها چندان سخت نخواهد بود. روی بالای مفهوم وعده ها تنها چیزی که واقعا باید بدانید این است هر قولی می تواند باشد await
-ed. ارزش ها نیز می توانند باشند await
-اد، درست مثل یک وعده .resolve()
روی یک عدد صحیح یا رشته
بیایید روش مبتنی بر Promise را با روش مقایسه کنیم await
کلمه کلیدی:
وعده ها
var request = require('request-promise');
request.get('https://api.github.com/repos/scottwrobinson/camo').then(function(body) {
console.log('Body:', body);
});
در انتظار
var request = require('request-promise');
async function main() {
var body = await request.get('https://api.github.com/repos/scottwrobinson/camo');
console.log('Body:', body);
}
main();
همانطور که می بینید، await
نشان می دهد که می خواهید Promise را حل کنید و آن شیء واقعی Promise را برنگردانید همانطور که به طور معمول انجام می شود. هنگامی که این خط اجرا می شود، request
تماس برقرار خواهد شد روی پشته و اجرای حلقه رویداد به کدهای ناهمزمان دیگری که آماده پردازش هستند، می رسد.
را async
کلمه کلیدی زمانی استفاده می شود که تابعی را تعریف می کنید که حاوی کد ناهمزمان است. این نشانگر این است که یک Promise از تابع برگردانده شده است و بنابراین باید به عنوان ناهمزمان در نظر گرفته شود.
در اینجا یک مثال ساده از استفاده از آن است (به تغییر در تعریف تابع توجه کنید):
async function getCamoJson() {
var options = {
url: 'https://api.github.com/repos/scottwrobinson/camo',
headers: {
'User-Agent': 'YOUR-GITHUB-USERNAME'
}
};
return await request.get(options);
}
var body = await getCamoJson();
حالا که می دانیم چگونه از آن استفاده کنیم async
و await
با هم، بیایید ببینیم کد پیچیدهتر مبتنی بر Promise از قبل در حال حاضر چگونه به نظر میرسد:
"use strict";
var request = require('request-promise');
var headers = {
'User-Agent': 'scottwrobinson'
};
var repos = (
'scottwrobinson/camo',
'facebook/react',
'scottwrobinson/twentyjs',
'moment/moment',
'nodejs/node',
'lodash/lodash'
);
var issueTitles = ();
async function main() {
for (let i = 0; i < repos.length; i++) {
let options = { url: 'https://api.github.com/repos/' + repos(i), headers: headers };
let body = await request.get(options);
let json = JSON.parse(body);
if (json.has_issues) {
let issuesOptions = { url: 'https://api.github.com/repos/' + repos(i) + '/issues', headers: headers };
let ibody = await request.get(issuesOptions);
let issuesJson = JSON.parse(ibody);
if (issuesJson(0)) {
issueTitles.push(issuesJson(0).title);
}
}
}
console.log('Issue titles:');
issueTitles.forEach(function(t) {
console.log
});
}
main();
مطمئناً اکنون قابل خواندن تر است که می توان آن را مانند بسیاری از زبان های دیگر که به صورت خطی اجرا می شوند، نوشت.
حالا تنها مشکل این است که هر کدام request.get()
فراخوانی به صورت سری اجرا میشود (یعنی هر تماس باید منتظر بماند تا تماس قبلی قبل از اجرا به پایان برسد)، بنابراین قبل از دریافت نتایج باید بیشتر منتظر بمانیم تا کد اجرا شود. گزینه بهتر این است که درخواست های HTTP GET را به صورت موازی اجرا کنید. هنوز هم می توان با استفاده از آن این کار را انجام داد Promise.all()
همانطور که قبلا انجام می دادیم فقط تعویض کنید for
حلقه با a .map()
تماس بگیرید و آرایه حاصل از Promises را به Promise.all()
، مثل این:
// Init code omitted...
async function main() {
let reqs = repos.map(async function(r) {
let options = { url: 'https://api.github.com/repos/' + r, headers: headers };
let body = await request.get(options);
let json = JSON.parse(body);
if (json.has_issues) {
let issuesOptions = { url: 'https://api.github.com/repos/' + r + '/issues', headers: headers };
let ibody = await request.get(issuesOptions);
let issuesJson = JSON.parse(ibody);
if (issuesJson(0)) {
issueTitles.push(issuesJson(0).title);
}
}
});
await Promise.all(reqs);
}
main();
به این ترتیب می توانید از سرعت اجرای موازی بهره ببرید و سادگی await
.
مزایای بیشتری نسبت به استفاده از جریان کنترل سنتی مانند حلقه ها و شرطی ها وجود دارد. این رویکرد خطی به ما امکان می دهد به استفاده از آن برگردیم try...catch
بیانیه رسیدگی به خطاها با Promises باید از .catch()
روشی که کارساز بود، اما میتواند باعث سردرگمی در تعیین اینکه کدام وعدهها برای آن استثنا شده است.
خب حالا این …
request.get('https://api.github.com/repos/scottwrobinson/camo').then(function(body) {
console.log(body);
}).catch(function(err) {
console.log('Got an error:', err.message);
});
// Got an error: 403 - "Request forbidden by administrative rules. Please make sure your request has a User-Agent header..."
را می توان اینگونه بیان کرد:
try {
var body = await request.get('https://api.github.com/repos/scottwrobinson/camo');
console.log(body);
} catch(err) {
console.log('Got an error:', err.message)
}
// Got an error: 403 - "Request forbidden by administrative rules. Please make sure your request has a User-Agent header..."
در حالی که تقریباً همان مقدار کد است، خواندن و درک آن برای شخصی که از زبان دیگری به جاوا اسکریپت منتقل می شود بسیار آسان تر است.
استفاده از Async در حال حاضر
ویژگی async هنوز در مرحله پیشنهاد است، اما نگران نباشید، هنوز چند راه وجود دارد که می توانید از آن در کد خود استفاده کنید. همین الان.
V8
در حالی که هنوز کاملاً به Node راه پیدا نکرده است، تیم V8 موفق شده است علنی اعلام کرد قصد آنها برای اجرای async
/await
ویژگی. آنها حتی پیشنمونه اجرای زمان اجرا را نیز متعهد کردهاند، که به این معنی است که پشتیبانی هارمونی نباید خیلی عقب باشد.
بابل
مسلماً محبوب ترین گزینه این است که کد خود را با استفاده از آن ترجمه کنید بابل و پلاگین های مختلف آن Babel به دلیل توانایی آن در ترکیب و تطبیق ویژگی های ES6 و ES7 با استفاده از سیستم پلاگین خود بسیار محبوب است. در حالی که تنظیم کمی پیچیده تر است، کنترل بسیار بیشتری را نیز در اختیار توسعه دهنده قرار می دهد.
احیا کننده
را احیا کننده پروژه فیس بوک به اندازه Babel ویژگی ندارد، اما راه ساده تری برای به کار انداختن ترانسپیلینگ ناهمگام است.
بزرگترین مشکلی که با آن داشته ام این است که خطاهای آن خیلی توصیفی نیستند. بنابراین اگر یک خطای نحوی در کد شما وجود داشته باشد، در یافتن آن از Regenerator کمک زیادی دریافت نخواهید کرد. غیر از این، من از آن راضی بودم.
ردیاب
من شخصاً تجربه ای در این مورد ندارم، اما ردیاب (توسط گوگل) به نظر می رسد یکی دیگر از گزینه های محبوب با بسیاری از ویژگی های موجود باشد. می توانید اطلاعات بیشتری پیدا کنید اینجا برای جزئیات روی چه ویژگی های ES6 و ES7 را می توان انتقال داد.
غیرقابل انتظار
بسیاری از گزینه های موجود برای شما شامل انتقال یا استفاده از یک ساخت شبانه V8 برای دریافت است async
کار کردن. گزینه دیگر استفاده از غیرقابل انتظار بسته، که عملکردی را برای حل و فصل Promises به طور مشابه ارائه می دهد await
ویژگی. این یک راه خوب وانیلی ES5 برای به دست آوردن نحو مشابه است.
نتیجه
و بس! من شخصاً بیشتر از همه در مورد این ویژگی در ES7 هیجان زده هستم، اما برخی دیگر نیز وجود دارد ویژگی های عالی در ES7 که باید آنها را بررسی کنید، مانند دکوراتورهای کلاس و خواص.
آیا از کد ES7 ترجمه شده استفاده می کنید؟ اگر بله، کدام ویژگی برای کار شما مفیدتر بوده است؟ در نظرات به ما اطلاع دهید!
(برچسبها برای ترجمه)# جاوا اسکریپت
منتشر شده در 1403-01-28 15:40:04