17 KiB
پروژه افزونه مرورگر بخش ۲: فراخوانی یک API، استفاده از Local Storage
آزمون پیش از درس
مقدمه
در این درس، شما با ارسال فرم افزونه مرورگر خود یک API را فراخوانی کرده و نتایج را در افزونه مرورگر نمایش خواهید داد. علاوه بر این، یاد خواهید گرفت که چگونه میتوانید دادهها را در حافظه محلی مرورگر (Local Storage) برای استفاده و مراجعه در آینده ذخیره کنید.
✅ بخشهای شمارهگذاریشده در فایلهای مربوطه را دنبال کنید تا بدانید کجا باید کد خود را قرار دهید.
تنظیم عناصر برای دستکاری در افزونه:
تا این مرحله، شما HTML مربوط به فرم و <div>
نتایج را برای افزونه مرورگر خود ساختهاید. از اینجا به بعد، باید در فایل /src/index.js
کار کنید و افزونه خود را به تدریج بسازید. به درس قبلی مراجعه کنید تا پروژه خود را تنظیم کرده و فرآیند ساخت را مرور کنید.
در فایل index.js
خود، با ایجاد چند متغیر const
شروع کنید تا مقادیر مرتبط با فیلدهای مختلف را نگه دارید:
// form fields
const form = document.querySelector('.form-data');
const region = document.querySelector('.region-name');
const apiKey = document.querySelector('.api-key');
// results
const errors = document.querySelector('.errors');
const loading = document.querySelector('.loading');
const results = document.querySelector('.result-container');
const usage = document.querySelector('.carbon-usage');
const fossilfuel = document.querySelector('.fossil-fuel');
const myregion = document.querySelector('.my-region');
const clearBtn = document.querySelector('.clear-btn');
تمام این فیلدها با استفاده از کلاس CSS که در درس قبلی در HTML تنظیم کردهاید، ارجاع داده میشوند.
افزودن شنوندهها (Listeners)
در مرحله بعد، شنوندههای رویداد را به فرم و دکمه پاکسازی اضافه کنید تا اگر کاربر فرم را ارسال کرد یا روی دکمه بازنشانی کلیک کرد، عملی انجام شود. همچنین، فراخوانی برای مقداردهی اولیه برنامه را در انتهای فایل اضافه کنید:
form.addEventListener('submit', (e) => handleSubmit(e));
clearBtn.addEventListener('click', (e) => reset(e));
init();
✅ به اختصار استفادهشده برای گوش دادن به رویداد ارسال یا کلیک توجه کنید و اینکه چگونه رویداد به توابع handleSubmit یا reset ارسال میشود. آیا میتوانید معادل این اختصار را به صورت طولانیتر بنویسید؟ کدام روش را ترجیح میدهید؟
ساخت توابع init() و reset():
اکنون شما باید تابعی که افزونه را مقداردهی اولیه میکند، یعنی init()، بسازید:
function init() {
//if anything is in localStorage, pick it up
const storedApiKey = localStorage.getItem('apiKey');
const storedRegion = localStorage.getItem('regionName');
//set icon to be generic green
//todo
if (storedApiKey === null || storedRegion === null) {
//if we don't have the keys, show the form
form.style.display = 'block';
results.style.display = 'none';
loading.style.display = 'none';
clearBtn.style.display = 'none';
errors.textContent = '';
} else {
//if we have saved keys/regions in localStorage, show results when they load
displayCarbonUsage(storedApiKey, storedRegion);
results.style.display = 'none';
form.style.display = 'none';
clearBtn.style.display = 'block';
}
};
function reset(e) {
e.preventDefault();
//clear local storage for region only
localStorage.removeItem('regionName');
init();
}
در این تابع، منطق جالبی وجود دارد. با خواندن آن، میتوانید ببینید چه اتفاقی میافتد؟
- دو
const
تنظیم میشوند تا بررسی کنند آیا کاربر یک APIKey و کد منطقه را در حافظه محلی ذخیره کرده است یا خیر. - اگر هر یک از این مقادیر null باشد، فرم را با تغییر سبک آن به 'block' نمایش دهید.
- بخش نتایج، بارگذاری و دکمه پاکسازی را مخفی کنید و هر متن خطا را به یک رشته خالی تنظیم کنید.
- اگر کلید و منطقهای وجود داشته باشد، یک روال برای:
- فراخوانی API برای دریافت دادههای مصرف کربن
- مخفی کردن بخش نتایج
- مخفی کردن فرم
- نمایش دکمه بازنشانی
قبل از ادامه، مفید است که درباره یک مفهوم بسیار مهم موجود در مرورگرها یاد بگیرید: LocalStorage. LocalStorage یک روش مفید برای ذخیره رشتهها در مرورگر به صورت جفت کلید-مقدار
است. این نوع ذخیرهسازی وب میتواند توسط جاوااسکریپت برای مدیریت دادهها در مرورگر دستکاری شود. LocalStorage منقضی نمیشود، در حالی که SessionStorage، نوع دیگری از ذخیرهسازی وب، هنگام بسته شدن مرورگر پاک میشود. انواع مختلف ذخیرهسازی مزایا و معایب خاص خود را دارند.
توجه - افزونه مرورگر شما حافظه محلی مخصوص به خود را دارد؛ پنجره اصلی مرورگر یک نمونه جداگانه است و به طور جداگانه عمل میکند.
شما مقدار APIKey خود را به عنوان یک رشته تنظیم میکنید، برای مثال، و میتوانید ببینید که این مقدار در Edge با "بازرسی" یک صفحه وب (میتوانید روی مرورگر راست کلیک کرده و بازرسی کنید) و رفتن به تب Applications برای مشاهده ذخیرهسازی تنظیم شده است.
✅ به موقعیتهایی فکر کنید که نمیخواهید برخی دادهها را در LocalStorage ذخیره کنید. به طور کلی، قرار دادن API Keys در LocalStorage ایده بدی است! آیا میتوانید دلیل آن را ببینید؟ در مورد ما، از آنجا که برنامه ما صرفاً برای یادگیری است و در فروشگاه برنامه منتشر نخواهد شد، از این روش استفاده خواهیم کرد.
توجه کنید که از Web API برای دستکاری LocalStorage استفاده میکنید، یا با استفاده از getItem()
، setItem()
یا removeItem()
. این روش به طور گسترده در مرورگرها پشتیبانی میشود.
قبل از ساخت تابع displayCarbonUsage()
که در init()
فراخوانی میشود، بیایید عملکردی برای مدیریت ارسال اولیه فرم بسازیم.
مدیریت ارسال فرم
یک تابع به نام handleSubmit
ایجاد کنید که یک آرگومان رویداد (e)
را میپذیرد. از انتشار رویداد جلوگیری کنید (در این مورد، میخواهیم از تازهسازی مرورگر جلوگیری کنیم) و یک تابع جدید به نام setUpUser
را فراخوانی کنید و آرگومانهای apiKey.value
و region.value
را به آن ارسال کنید. به این ترتیب، از دو مقداری که از طریق فرم اولیه وارد شدهاند استفاده میکنید.
function handleSubmit(e) {
e.preventDefault();
setUpUser(apiKey.value, region.value);
}
✅ حافظه خود را تازه کنید - HTML که در درس قبلی تنظیم کردهاید دارای دو فیلد ورودی است که مقادیر
آنها از طریق const
که در بالای فایل تنظیم کردهاید، گرفته میشود و هر دو required
هستند، بنابراین مرورگر از وارد کردن مقادیر null توسط کاربران جلوگیری میکند.
تنظیم کاربر
به تابع setUpUser
بروید، در اینجا مقادیر حافظه محلی برای apiKey و regionName تنظیم میشوند. یک تابع جدید اضافه کنید:
function setUpUser(apiKey, regionName) {
localStorage.setItem('apiKey', apiKey);
localStorage.setItem('regionName', regionName);
loading.style.display = 'block';
errors.textContent = '';
clearBtn.style.display = 'block';
//make initial call
displayCarbonUsage(apiKey, regionName);
}
این تابع یک پیام بارگذاری را برای نمایش در حین فراخوانی API تنظیم میکند. در این مرحله، شما به مهمترین تابع این افزونه مرورگر رسیدهاید!
نمایش مصرف کربن
در نهایت، زمان آن رسیده که API را پرسوجو کنید!
قبل از ادامه، باید درباره APIها صحبت کنیم. APIها یا رابطهای برنامهنویسی کاربردی، یک عنصر حیاتی در جعبه ابزار یک توسعهدهنده وب هستند. آنها روشهای استانداردی برای برنامهها فراهم میکنند تا با یکدیگر تعامل و ارتباط برقرار کنند. برای مثال، اگر در حال ساخت یک وبسایت هستید که نیاز به پرسوجو از یک پایگاه داده دارد، ممکن است کسی یک API برای شما ایجاد کرده باشد. در حالی که انواع مختلفی از APIها وجود دارد، یکی از محبوبترین آنها REST API است.
✅ اصطلاح 'REST' مخفف 'Representational State Transfer' است و شامل استفاده از URLهای مختلف برای دریافت دادهها میشود. کمی تحقیق کنید درباره انواع مختلف APIهایی که برای توسعهدهندگان در دسترس هستند. کدام فرمت برای شما جذابتر است؟
چند نکته مهم درباره این تابع وجود دارد. ابتدا، به کلمه کلیدی async
توجه کنید. نوشتن توابع به گونهای که به صورت ناهمگام اجرا شوند به این معناست که آنها منتظر یک عمل، مانند بازگشت دادهها، میمانند تا قبل از ادامه کار تکمیل شود.
در اینجا یک ویدیو کوتاه درباره async
وجود دارد:
🎥 روی تصویر بالا کلیک کنید تا ویدیویی درباره async/await ببینید.
یک تابع جدید برای پرسوجو از API C02Signal ایجاد کنید:
import axios from '../node_modules/axios';
async function displayCarbonUsage(apiKey, region) {
try {
await axios
.get('https://api.co2signal.com/v1/latest', {
params: {
countryCode: region,
},
headers: {
'auth-token': apiKey,
},
})
.then((response) => {
let CO2 = Math.floor(response.data.data.carbonIntensity);
//calculateColor(CO2);
loading.style.display = 'none';
form.style.display = 'none';
myregion.textContent = region;
usage.textContent =
Math.round(response.data.data.carbonIntensity) + ' grams (grams C02 emitted per kilowatt hour)';
fossilfuel.textContent =
response.data.data.fossilFuelPercentage.toFixed(2) +
'% (percentage of fossil fuels used to generate electricity)';
results.style.display = 'block';
});
} catch (error) {
console.log(error);
loading.style.display = 'none';
results.style.display = 'none';
errors.textContent = 'Sorry, we have no data for the region you have requested.';
}
}
این یک تابع بزرگ است. چه اتفاقی در اینجا میافتد؟
- با پیروی از بهترین شیوهها، از کلمه کلیدی
async
استفاده میکنید تا این تابع به صورت ناهمگام عمل کند. این تابع شامل یک بلوکtry/catch
است زیرا هنگام بازگشت دادهها از API یک وعده بازمیگرداند. از آنجا که شما کنترلی بر سرعت پاسخ API ندارید (ممکن است اصلاً پاسخ ندهد!)، باید این عدم قطعیت را با فراخوانی آن به صورت ناهمگام مدیریت کنید. - شما API co2signal را برای دریافت دادههای منطقه خود پرسوجو میکنید و از کلید API خود استفاده میکنید. برای استفاده از آن کلید، باید نوعی احراز هویت را در پارامترهای هدر خود قرار دهید.
- هنگامی که API پاسخ میدهد، عناصر مختلف دادههای پاسخ آن را به بخشهایی از صفحه که برای نمایش این دادهها تنظیم کردهاید، اختصاص میدهید.
- اگر خطایی وجود داشته باشد یا نتیجهای نباشد، یک پیام خطا نمایش میدهید.
✅ استفاده از الگوهای برنامهنویسی ناهمگام ابزار بسیار مفیدی در جعبه ابزار شماست. درباره روشهای مختلف پیکربندی این نوع کد مطالعه کنید.
تبریک میگویم! اگر افزونه خود را بسازید (npm run build
) و آن را در پنل افزونهها تازهسازی کنید، یک افزونه کاربردی خواهید داشت! تنها چیزی که کار نمیکند، آیکون است و آن را در درس بعدی درست خواهید کرد.
🚀 چالش
ما تاکنون درباره چند نوع API در این درسها صحبت کردهایم. یک API وب انتخاب کنید و به طور عمیق تحقیق کنید که چه امکاناتی ارائه میدهد. برای مثال، به APIهای موجود در مرورگرها مانند HTML Drag and Drop API نگاهی بیندازید. به نظر شما چه چیزی یک API عالی را میسازد؟
آزمون پس از درس
مرور و مطالعه شخصی
شما در این درس درباره LocalStorage و APIها یاد گرفتید، هر دو برای یک توسعهدهنده وب حرفهای بسیار مفید هستند. آیا میتوانید به این فکر کنید که چگونه این دو با هم کار میکنند؟ به این فکر کنید که چگونه یک وبسایت طراحی میکنید که آیتمهایی را برای استفاده توسط یک API ذخیره کند.
تکلیف
سلب مسئولیت:
این سند با استفاده از سرویس ترجمه هوش مصنوعی Co-op Translator ترجمه شده است. در حالی که ما تلاش میکنیم دقت را حفظ کنیم، لطفاً توجه داشته باشید که ترجمههای خودکار ممکن است شامل خطاها یا نادرستیهایی باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حساس، ترجمه حرفهای انسانی توصیه میشود. ما هیچ مسئولیتی در قبال سوءتفاهمها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.