完美约会:一个 Javascript 和 API 项目
AWS 安全上线!
我目前是 Flatiron 的学生。我们第一阶段的学习重点是 JavaScript 基础知识和 API 理解。在这一阶段的最后,我们需要将学习内容整合成一个单页应用,既能激发我们的兴趣,又能展示我们的理解。我想分享一下我的项目概况,以及项目中我遇到困难但最终受益匪浅的两个部分。
什么是 API 以及它们为何如此神奇
在我开始介绍我的项目之前,我们先来解释一下什么是 API。API 是“应用程序编程接口”的缩写,是两个应用程序之间相互通信的中介。
公司(例如 Google)或组织(例如政府)使用 API 与我们共享信息或功能,以便我们能够利用这些数据构建项目。市面上有免费的 API,任何人都可以访问。
在这个项目中,我使用了Weatherstack API。他们有一个免费版本,可以查看当前天气,但我付费使用了他们的历史天气数据库。API 提供了关于如何访问数据以及哪些数据可供使用的文档,方便您使用。
完美约会概述
我目前正处于婚礼筹备的初期阶段,而婚礼中最不可控的因素之一就是天气。但我可以通过选择一个历年天气都不错的婚礼日期来增加胜算。这就是“完美约会”应用的由来。它能让你根据历史天气数据来规划大型活动,无论是婚礼还是精彩的假期。
查看按地点和月份划分的平均天气数据
我的应用程序的第一部分是表单。你需要输入你想要查看天气数据的位置、月份和时间范围。时间范围可以选择从去年到过去五年的天气数据。
发出 API 请求后,系统会创建平均值的日历视图。以下示例显示了迈阿密 2021 年至 2020 年的平均数据。图标和天气描述显示的是聚合数据的模式。如果没有模式,则显示最新的图标和天气描述。
查看特定日期的天气日期细分
如果您点击某一天的“查看详情”,您可以看到按年份细分的天气数据。
保存日期并进行比较
如果你点击“保存此日期”,它会将数据保存到一个 JSON 服务器(我设置的本地服务器)。点击“查看所有已保存日期”,它会按地点细分你保存的日期。如果你保存了多个日期和地点,它会按地点细分日期。
应用程序问题和解决方案
我连续一周24小时不间断地思考这个应用,琢磨着遇到问题时该如何让它发挥作用。这其中包括半夜醒来,想着解决办法,然后把它们写下来,以便第二天早上第一时间就能用。这个应用出现了两个问题,让我一度想哭,因为我当时还没找到Flatiron的解决方案。
问题 1:从 API 分组数据
我遇到的第一个挑战是 Weatherstack API 每次只允许获取 60 天的历史天气数据。这意味着,根据要比较的年份,我必须每年分别向 API 请求一次数据。因此,我无法在 API 调用后立即计算数据平均值,而是需要先精确地存储和分组每次 API 调用的数据,然后再进行平均。
这个问题的第二部分是如何准确地对日期进行分组。我不想把每个月的3月1日归为一组,而是想把每个月的第一个星期五归为一组。这两个日期并不相同,因为日期每年会根据是否是闰年而移动一天或更多。
我的解决方案
我决定为每个月的星期和星期几的组合创建一个数组。根据您查看的月份和年份,日历上最多可以显示 6 周。如果一周有 7 天,那么总共有 42 种组合。(虽然我尽量避免使用 var 声明变量,但在本例中,这是我唯一可以声明变量的方法,而且它们仍然适用于我的解决方案)。
//create arrays to push API data. array push corresponds with week and day of week the object falls on
Var [week1Day0,week1Day1,week1Day2,week1Day3,week1Day4,week1Day5,week1Day6,week2Day0,week2Day1,week2Day2,week2Day3,week2Day4,week2Day5,week2Day6,week3Day0,week3Day1,week3Day2,week3Day3,week3Day4,week3Day5,week3Day6,week4Day0,week4Day1,week4Day2,week4Day3,week4Day4,week4Day5,week4Day6,week5Day0,week5Day1,week5Day2,week5Day3,week5Day4,week5Day5,week5Day6,week6Day0,week6Day1,week6Day2,week6Day3,week6Day4,week6Day5,week6Day6] = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]];
然后,我创建了两个函数来帮助我通过月份、年份、日期的参数来确定一天属于哪一周以及属于星期几。
//day of week
function dayOfWeek (month, year, day) {
let dayOfWeek = new Date(year, month, day).getDay();
return dayOfWeek;
}
// week of month
function weekOfMonth (day, start) {
return Math.ceil((day + start) / 7);
}
当我从 API 中获取时,提取的日期被格式化为以下格式的字符串。
{
"historical": {
"2021-03-01": {
"date": "2021-03-01",
"date_epoch": 1614556800,
"astro": {
"sunrise": "07:57 AM",
"sunset": "07:30 PM",
"moonrise": "10:18 PM",
"moonset": "09:41 AM",
"moon_phase": "Waning Gibbous",
"moon_illumination": 79
},
"mintemp": 50,
"maxtemp": 55,
"avgtemp": 54,
"totalsnow": 0,
"sunhour": 7.3,
"uv_index": 3,
"hourly": [...]
}
}
我需要将日期拆分,以便将其添加到我的函数中。拆分字符串后,我就能找到日期所在的星期和星期几。然后,我必须将日期推送到准确的数组中。我在网上很难找到如何创建并将数据推送到动态变量名的方法。如上所述,唯一有效的方法是将初始数组设置为 vars 而不是 const,然后使用 将日期对象推送到每个数组中window
。
理想情况下,我希望不声明空数组,而是在每个空数组出现时都创建一个动态变量名。我实在想不通该怎么做,所以这就是我的解决方案。
//push each date into the right array
for(const date in datesObject) {
const data = datesObject[date];
let dateArray = data.date.split('-');
let dateDay = parseInt(dateArray[2]);
let dateMonth = parseInt(dateArray[1]) - 1;
let dateDayOfWeek = dayOfWeek(dateMonth, dateArray[0], dateArray[2]);
let dateWeekOfMonth = weekOfMonth(dateDay, startDay);
window[`week${dateWeekOfMonth}Day${dateDayOfWeek}`].push(data);
}
问题 #2:等待 API 数据推送到数组后再创建平均值
通常,JavaScript 是同步运行的,并且是在单线程中运行的。这意味着它会等待上一行代码执行完毕后再执行下一行代码。然而,JavaScriptfetch
是异步的。这意味着 JavaScript 不会等待 API 请求完成就运行下一行代码。这对于网站来说通常是一件好事,因为您不知道请求执行的时间以及是否会返回,而且您也不希望用户永远等待页面加载。然而,这个项目仅用于获取 API 数据,并且 100% 依赖于 API 数据。
起初,API 的获取请求会发送,但之后我的日历会创建为空,li
因为它会在没有 API 数据的情况下继续运行我的代码。实际上,我需要停止其余代码的运行,只有在获取到 API 数据后才继续运行。
我的解决方案
我在网上找到的解决方案是异步函数。我并不想声称自己掌握了所有关于异步函数的知识,但我发现这个视频很有帮助,它解释了异步函数以及如何创建它们。本质上,异步函数允许你使用关键字 await。这使得函数在运行下一行代码之前“等待”一个 Promise 返回。这意味着我必须将我的fetchSubmit
和createDatesInCalendar
函数分别包装在一个 Promise 中,然后将它们传递回我的异步函数。一旦我创建了异步函数,它就按预期工作了!
//example of my createDatesInCalendar function wrapped in a promise
function createDatesInCalendar() {
return new Promise(resolve => {
var dayOfMonthArrays = [week1Day0,week1Day1,week1Day2,week1Day3,week1Day4,week1Day5,week1Day6,week2Day0,week2Day1,week2Day2,week2Day3,week2Day4,week2Day5,week2Day6,week3Day0,week3Day1,week3Day2,week3Day3,week3Day4,week3Day5,week3Day6,week4Day0,week4Day1,week4Day2,week4Day3,week4Day4,week4Day5,week4Day6,week5Day0,week5Day1,week5Day2,week5Day3,week5Day4,week5Day5,week5Day6,week6Day0,week6Day1,week6Day2,week6Day3,week6Day4,week6Day5,week6Day6]
dayOfMonthArrays.forEach(day => {
let id;
//if array is empty create empty list item else create list item with array info
if (day.length === 0){
id = dayOfMonthArrays.indexOf(day);
emptyLi(id);
} else {
let newObject = {};
id = dayOfMonthArrays.indexOf(day);
createAverageObjects(day, newObject, id);
}
//save arrays with API objects into new array so we can access data later
return dateArrayObject.push(day);
});
resolve('day averages function finished');
});
}
//how many times to fetch API data (fetch for each year of data). wait for fetches to be done before calculating averages
if(timeframeIndex === 0){
async function getData(){
await fetchSubmit(locationInput, monthNum, monthIndex, year1, numDays);
await createDatesInCalendar();
}
getData();
} else if(timeframeIndex === 1){
async function getData(){
await fetchSubmit(locationInput, monthNum, monthIndex, year1, numDays);
await fetchSubmit(locationInput, monthNum, monthIndex, year2, numDays);
await createDatesInCalendar();
}
getData();
} else if(timeframeIndex === 2) {
async function getData(){
await fetchSubmit(locationInput, monthNum, monthIndex, year1, numDays);
await fetchSubmit(locationInput, monthNum, monthIndex, year2, numDays);
await fetchSubmit(locationInput, monthNum, monthIndex, year3, numDays);
await createDatesInCalendar();
}
getData();
} else if(timeframeIndex === 3){
async function getData(){
await fetchSubmit(locationInput, monthNum, monthIndex, year1, numDays);
await fetchSubmit(locationInput, monthNum, monthIndex, year2, numDays);
await fetchSubmit(locationInput, monthNum, monthIndex, year3, numDays);
await fetchSubmit(locationInput, monthNum, monthIndex, year4, numDays);
await createDatesInCalendar();
}
getData();
} else {
async function getData(){
await fetchSubmit(locationInput, monthNum, monthIndex, year1, numDays);
await fetchSubmit(locationInput, monthNum, monthIndex, year2, numDays);
await fetchSubmit(locationInput, monthNum, monthIndex, year3, numDays);
await fetchSubmit(locationInput, monthNum, monthIndex, year4, numDays);
await fetchSubmit(locationInput, monthNum, monthIndex, year5, numDays);
await createDatesInCalendar();
}
getData();
}
最后的想法
开发这款应用对我来说是一个巨大的挑战,但我非常享受这个过程。我希望对它进行一些改进,比如更好地组织已保存日期的页面,并支持选择已保存日期进行并排比较。
我对 JavaScript 和 API 还不熟悉,所以如果你有更好的解决方案,请在评论区分享!我觉得上面的代码可以更简洁一些,或者更短一些,我一直在努力改进我的编码。
鏂囩珷鏉ユ簮锛�https://dev.to/christinecontreras/perfect-date-a-javascript-and-api-project-1hng