JavaScript - result undefined - forcing one method to complete before another? - javascript

I have the following NodeJS code running in an AWS Lambda:
const https = require('https');
exports.handler = async event => {
try {
const currentWeekNumber = getWeekNumber(new Date(Date.now()));
const currentTournamentId = await getCurrentTournamentIdByWeekNumber(currentWeekNumber);
// note: Issue is currentTournamentId is returned as undefined from above, so below method fails
const leaderBoard = await getLeaderboardByTournId(currentTournamentId);
return {
statusCode: 200,
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(leaderBoard),
};
} catch (error) {
console.log('Error: ️', error);
return {
statusCode: 400,
body: error.message,
};
}
};
function getCurrentTournamentIdByWeekNumber(currentWeekNumber) {
const promise = new Promise((resolve, reject) => {
const options = {
host: 'MY_HOST',
path: '/MY_PATH',
headers: {
'key': 'value'
}
};
const req = https.get(options, res => {
let rawData = '';
res.on('data', chunk => {
rawData += chunk;
});
res.on('end', () => {
try {
resolve(JSON.parse(rawData));
} catch (err) {
reject(new Error(err));
}
});
});
req.on('error', err => {
reject(new Error(err));
});
});
promise.then(result => {
for (let i = 0; i <result.schedule.length; i++) {
let weekNumber = result.schedule[i].date.weekNumber;
if(currentWeekNumber == weekNumber) {
return result.schedule[i].tournId;
}
}
});
}
function getLeaderboardByTournId(tournId) {
return new Promise((resolve, reject) => {
const options = {
host: 'MY_HOST',
path: '/MY_PATH',
headers: {
'key': 'value'
}
};
const req = https.get(options, res => {
let rawData = '';
res.on('data', chunk => {
rawData += chunk;
});
res.on('end', () => {
try {
resolve(JSON.parse(rawData));
} catch (err) {
reject(new Error(err));
}
});
});
req.on('error', err => {
reject(new Error(err));
});
});
}
function getWeekNumber(d) {
// Copy date so don't modify original
d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
// Set to nearest Thursday: current date + 4 - current day number
// Make Sunday's day number 7
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay()||7));
// Get first day of year
var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
// Calculate full weeks to nearest Thursday
var weekNo = Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7);
// Return array of year and week number
return weekNo;
}
I am having an issue where currentTournamentId is being passed into getLeaderboardByTournId as undefined, I think this is due to the execution order of my functions.
I know that the logic is correct in all the functions.
How can I ensure that getCurrentTournamentIdByWeekNumber completes and returns a result before getLeaderboardByTournId is called?
This is my first attempt at node lambda and only getting to grips with JS execution order!

You are correctly awaiting your getCurrentTournamentIdByWeekNumber method, however inside of that method, you're not returning anything so there's no promise to wait for.
If you're add a return it will probably work:
return promise.then(result => {
...

Related

Exponential Backoff not returning data in promise

I am not sure if I am approaching this the correct way. I have tried a few different versions of the implementation but am putting the one here that works when the backoff path is NOT used.
So, I have an index.js that is just:
import { Lizard } from './lizard.js';
const lizard = new Lizard();
const global_data = await lizard.global();
console.log(global_data);
In my lizard.js I have a class with functions but for the sake of saving space and noise I will only place the ones that matter here:
export class Lizard {
global() {
const path = '/global';
return this._request(path);
};
_buildRequestOptions(path, params) {
if (isObject(params)) params = querystring.stringify(params);
else params = undefined;
if (params == undefined) path = `/api/v${API_VERSION}${path}`;
else path = `/api/v${API_VERSION}${path}?${params}`;
// Return options
return {
path,
method: 'GET',
host: HOST,
port: 443,
timeout: Lizard.TIMEOUT,
};
};
async _request(path, params) {
const options = this._buildRequestOptions(path, params);
const maxRetries = 10;
function waitFor(milliseconds) {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function request(options, retries) {
if (retries > 0) {
const timeToWait = 15000 * retries;
console.log(`waiting for ${timeToWait}ms...`);
await waitFor(timeToWait);
}
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
let body = [];
res.on('data', (chunk) => {
body.push(chunk);
});
res.on('end', () => {
try {
body = Buffer.concat(body);
body = body.toString();
if (body.startsWith('<!DOCTYPE html>')) {
_WARN_('Invalid request', 'There was a problem with your request. The parameter(s) you gave are missing or incorrect.');
} else if (body.startsWith('Throttled')) {
_WARN_('Throttled request', 'There was a problem with request limit.');
}
body = JSON.parse(body);
} catch (error) {
reject(error);
};
const returnObject = ReturnObject(
!(res.statusCode < 200 || res.statusCode >= 300),
res.statusMessage,
res.statusCode,
body
)
if (returnObject.code != 429) {
resolve(returnObject);
} else {
if (retries < maxRetries) {
console.log('retrying...');
return request(options, retries + 1);
} else {
console.log("Max retries reached. Bubbling the error up");
resolve(returnObject);
}
}
});
});
req.on('error', (error) => reject(error));
req.on('timeout', () => {
req.abort();
reject(new Error(`Lizard API request timed out. Current timeout is: ${Lizard.TIMEOUT} milliseconds`));
});
// End request
req.end();
});
}
return await request(options, 0);
};
}
I was trying to do this in a very difficult way. For anyone else that may stumble upon this here was my ultimate solution:
lizard.js:
async function request(path, params, retries = 0, maxRetries = 10) {
let options = await buildRequestOptions(path, params);
return new Promise((resolve, reject) => {
let req = https.request(options, (res) => {
let body = [];
// Set body on data
res.on('data', (chunk) => {
body.push(chunk);
});
// On end, end the Promise
res.on('end', async () => {
try {
body = Buffer.concat(body);
body = body.toString();
// Check if page is returned instead of JSON
if (body.startsWith('<!DOCTYPE html>')) {
_WARN_('Invalid request', 'There was a problem with your request. The parameter(s) you gave are missing or incorrect.');
} else if (body.startsWith('Throttled')) {
_WARN_('Throttled request', 'There was a problem with request limit.');
}
// Attempt to parse
body = JSON.parse(body);
} catch (error) {
reject(error);
};
if (res.statusCode == 429 && retries < maxRetries) {
const timeToWait = 60000 + (1000 * retries);
console.error('Throttled request ' + retries + ' time(s)');
console.log(`Retrying in ${timeToWait}ms...`);
setTimeout(() => {
resolve(request(path, params, retries + 1));
}, timeToWait);
} else {
resolve(
objectify(
!(res.statusCode < 200 || res.statusCode >= 300),
res.statusMessage,
res.statusCode,
body
)
);
}
});
});
// On error, reject the Promise
req.on('error', (error) => reject(error));
// On timeout, reject the Promise
req.on('timeout', () => {
req.abort();
reject(new Error(`Lizard API request timed out. Current timeout is: ${TIMEOUT} milliseconds`));
});
// End request
req.end();
});
};
I still resolve the object on fail as 429 is too many requests, so anything else needs to bubble up. On top of that if max retries is met, then if I see a 429 I know that I exceeded.

How to wait for function to finish before running another one or rest of the code?

I can't figure this one out. I have one function that connects to an SFTP server and downloads files. Then, I have a second function that reads the contents, puts the data in an array, and returns the array.
The problem is that the second function always runs first. I tried different methods but I can't get it to work. That connection to SFTP is quite slow, it can take like 10+ seconds to finish. But I need to somehow wait for it to finish before doing anything else.
const SFTPConfig = require('../config/keys').sftpconfig;
const getCSATFiles = async function(targetDate) {
try {
let Client = require('ssh2-sftp-client');
let sftp = new Client();
const date = moment(targetDate);
var dir = `../csv/${targetDate}/`;
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
sftp
.connect(SFTPConfig, 'once')
.then(() => {
return sftp.list('/In/Archives/');
})
.then(data => {
data.forEach(item => {
const fileName = item.name;
const remotePath = '/In/Archives/' + fileName;
const localePath = path.join(dir + fileName);
if (
moment(item.modifyTime)
.format('YYYY-MM-DD hh:mm')
.toString()
.slice(0, 10) ===
date
.format('YYYY-MM-DD hh:mm')
.toString()
.slice(0, 10)
) {
sftp
.fastGet(remotePath, localePath, {})
.then(() => {
console.log('finished getting the files!');
sftp.end();
})
.catch(err => {
sftp.end();
console.log(err, 'fastGet method error');
});
}
});
});
} catch (error) {
console.log(error);
}
};
const readCSVFiles = async function(targetDate) {
try {
const casesBO = [];
var dir = `../csv/${targetDate}/`;
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
const allLocalFiles = path.join(__dirname, dir);
const readDir = util.promisify(fs.readdir);
const files = await readDir(allLocalFiles);
for (let file of files) {
fs.createReadStream(allLocalFiles + file)
.pipe(csv.parse({ headers: true, delimiter: ';' }))
.on('error', error => console.error(error))
.on('data', row => {
if (row['[REGION2]'] !== 'FR') {
casesBO.push(row['[CALLERNO_EMAIL_SOCIAL]']);
console.log(
`${row['[AGENT]']} is ${row['[REGION2]']} and case = ${
row['[CALLERNO_EMAIL_SOCIAL]']
}`
);
}
})
.on('end', rowCount => {
console.log(`Parsed ${rowCount} rows`);
});
}
return casesBO;
} catch (error) {
console.log(error);
}
};
const testFunc = async () => {
const csatfiles = await getCSATFiles('2021-02-03');
const boData = await readCSVFiles('2021-02-03');
console.log(boData);
};
testFunc();
#1 as #messerbill suggested, you need to return the promise from your function.
#2 your promise has a loop inside of it that have more promises. In this case, you need to collect those promises and use Promise.all to resolve them before you second function runs. I put comments on the lines you need to change below. Try this:
const SFTPConfig = require('../config/keys').sftpconfig;
const getCSATFiles = function(targetDate) {
try {
let Client = require('ssh2-sftp-client');
let sftp = new Client();
const date = moment(targetDate);
var dir = `../csv/${targetDate}/`;
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
// I return the promise here
return sftp
.connect(SFTPConfig, 'once')
.then(() => {
return sftp.list('/In/Archives/');
})
.then(data => {
// I set up my promises as a blank array
const promises = [];
data.forEach(item => {
const fileName = item.name;
const remotePath = '/In/Archives/' + fileName;
const localePath = path.join(dir + fileName);
if (
moment(item.modifyTime)
.format('YYYY-MM-DD hh:mm')
.toString()
.slice(0, 10) ===
date
.format('YYYY-MM-DD hh:mm')
.toString()
.slice(0, 10)
) {
// I collect the promises here
promises.push(sftp
.fastGet(remotePath, localePath, {})
.then(() => {
console.log('finished getting the files!');
sftp.end();
})
.catch(err => {
sftp.end();
console.log(err, 'fastGet method error');
}));
}
});
// I resolve them here
return Promise.all(promises);
});
} catch (error) {
console.log(error);
}
};
const readCSVFiles = async function(targetDate) {
try {
const casesBO = [];
var dir = `../csv/${targetDate}/`;
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
const allLocalFiles = path.join(__dirname, dir);
const readDir = util.promisify(fs.readdir);
const files = await readDir(allLocalFiles);
for (let file of files) {
fs.createReadStream(allLocalFiles + file)
.pipe(csv.parse({ headers: true, delimiter: ';' }))
.on('error', error => console.error(error))
.on('data', row => {
if (row['[REGION2]'] !== 'FR') {
casesBO.push(row['[CALLERNO_EMAIL_SOCIAL]']);
console.log(
`${row['[AGENT]']} is ${row['[REGION2]']} and case = ${
row['[CALLERNO_EMAIL_SOCIAL]']
}`
);
}
})
.on('end', rowCount => {
console.log(`Parsed ${rowCount} rows`);
});
}
return casesBO;
} catch (error) {
console.log(error);
}
};
const testFunc = async () => {
const csatfiles = await getCSATFiles('2021-02-03');
const boData = await readCSVFiles('2021-02-03');
console.log(boData);
};
testFunc();
You need to take care, that you return the promise you want to resolve inside the function body in order to get the promise resolved at the right time.
async function promiseNotReturned() {
new Promise(resolve => setTimeout(resolve.bind(null), 5000))
}
async function promiseReturned() {
return new Promise(resolve => setTimeout(resolve.bind(null), 5000))
}
async function run() {
await promiseNotReturned()
console.log("does not wait for 5 seconds")
await promiseReturned()
console.log("waits for 5 seconds")
}
run()

AWS Lambda function handler not inserting to Athena

I'm using a snippet example for Amazon Athena just to test inserting some data. I can't tell why it isn't working and CloudWatch logs does not show any output when the statement execution is completed. Even when I change it to a simple select statement I can't see any output. I know the query, database and table is fine, because when I test it using the Athena query editor it executes without a problem.
module.exports.dlr = async event => {
let awsFileCreds = {
accessKeyId: "XXX",
secretAccessKey: "XXX"
};
let creds = new AWS.Credentials(awsFileCreds);
AWS.config.credentials = creds;
let client = new AWS.Athena({ region: "eu-west-1" });
let q = Queue((id, cb) => {
startPolling(id)
.then(data => {
return cb(null, data);
})
.catch(err => {
console.log("Failed to poll query: ", err);
return cb(err);
});
}, 5);
const sql = "INSERT INTO delivery_receipts (status, eventid, mcc, mnc, msgcount, msisdn, received, userreference) VALUES ('TestDLR', 345345, 4353, '5345435', 234, '345754', 234, '8833')"
makeQuery(sql)
.then(data => {
console.log("Row Count: ", data.length);
console.log("DATA: ", data);
})
.catch(e => {
console.log("ERROR: ", e);
});
function makeQuery(sql) {
return new Promise((resolve, reject) => {
let params = {
QueryString: sql,
ResultConfiguration: { OutputLocation: ATHENA_OUTPUT_LOCATION },
QueryExecutionContext: { Database: ATHENA_DB }
};
client.startQueryExecution(params, (err, results) => {
if (err) return reject(err);
q.push(results.QueryExecutionId, (err, qid) => {
if (err) return reject(err);
return buildResults(qid)
.then(data => {
return resolve(data);
})
.catch(err => {
return reject(err);
});
});
});
});
}
function buildResults(query_id, max, page) {
let max_num_results = max ? max : RESULT_SIZE;
let page_token = page ? page : undefined;
return new Promise((resolve, reject) => {
let params = {
QueryExecutionId: query_id,
MaxResults: max_num_results,
NextToken: page_token
};
let dataBlob = [];
go(params);
function go(param) {
getResults(param)
.then(res => {
dataBlob = _.concat(dataBlob, res.list);
if (res.next) {
param.NextToken = res.next;
return go(param);
} else return resolve(dataBlob);
})
.catch(err => {
return reject(err);
});
}
function getResults() {
return new Promise((resolve, reject) => {
client.getQueryResults(params, (err, data) => {
if (err) return reject(err);
var list = [];
let header = buildHeader(
data.ResultSet.ResultSetMetadata.ColumnInfo
);
let top_row = _.map(_.head(data.ResultSet.Rows).Data, n => {
return n.VarCharValue;
});
let resultSet =
_.difference(header, top_row).length > 0
? data.ResultSet.Rows
: _.drop(data.ResultSet.Rows);
resultSet.forEach(item => {
list.push(
_.zipObject(
header,
_.map(item.Data, n => {
return n.VarCharValue;
})
)
);
});
return resolve({
next: "NextToken" in data ? data.NextToken : undefined,
list: list
});
});
});
}
});
}
function startPolling(id) {
return new Promise((resolve, reject) => {
function poll(id) {
client.getQueryExecution({ QueryExecutionId: id }, (err, data) => {
if (err) return reject(err);
if (data.QueryExecution.Status.State === "SUCCEEDED")
return resolve(id);
else if (
["FAILED", "CANCELLED"].includes(data.QueryExecution.Status.State)
)
return reject(
new Error(`Query ${data.QueryExecution.Status.State}`)
);
else {
setTimeout(poll, POLL_INTERVAL, id);
}
});
}
poll(id);
});
}
function buildHeader(columns) {
return _.map(columns, i => {
return i.Name;
});
}
return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};
Figured it out. Using aws lambda events with athena is easy using the athena-express package. You can specify your configuration and query the athena database like you normally would with significantly less code than what's provided in the amazon athena nodejs example.
This is the code I used to achieve a result:
"use strict";
const AthenaExpress = require("athena-express"),
aws = require("aws-sdk");
const athenaExpressConfig = {
aws,
db: "messaging",
getStats: true
};
const athenaExpress = new AthenaExpress(athenaExpressConfig);
exports.handler = async event => {
const sqlQuery = "SELECT * FROM delivery_receipts LIMIT 3";
try {
let results = await athenaExpress.query(sqlQuery);
return results;
} catch (error) {
return error;
}
};

How can i use await, when it's don't recognize?

I'm trying to use await on var application = await SchedulerService().getIssues(issueId)
And it returns the error: SyntaxError: await is only valid in async function
I'm starting in node.js. What can I do to fix it?
I've tried already
Add async before initial function const SchedulerService = await function(){ at line 1
Add async on first return return async () => { where's return { at line 3
import schedulerConf from '../../config/scheduler';
import authConf from '../../config/auth';
import applicationConf from '../../config/application';
import request from 'request';
import schedule from 'node-schedule';
import dateformat from 'dateformat';
let interations = 0;
var serviceRecords = [];
var issueRecords = [];
const SchedulerService = function(){
return {
initialize: async () => {
console.log(`***** Starting Scheduler on ${dateformat(new Date(), "dd/mm/yyyy HH:MM:ss")}`);
var j = schedule.scheduleJob('*/1 * * * *', function(){
console.time('└─ Scheduler execution time');
if(interations === 0){
console.log(`Setting scheduler runtime to full time.`);
}else{
console.log(`------------------------`);
}
interations++;
console.log(`Job execution number: ${interations}.`);
SchedulerService().execute()
.then(response => {
console.log(`└─ Job ${interations} was successfully executed.`);
console.log(`└─ Execution date ${dateformat(new Date(), "dd/mm/yyyy HH:MM:ss")}`);
console.timeEnd('└─ Scheduler execution time');
}).catch(error => {
console.log(`└─ Job ${interations} returned error while executing.`);
});
});
},
execute: async () => {
return SchedulerService().getRecords2Sync()
.then(() => {
SchedulerService().sync().then(() => {
}).catch(error => {console.log({error})});
}).catch(error => {console.log({error})});
},
getRecords2Sync: async () => {
serviceRecords = [];
var options = {
url: `http://localhost:${authConf.serverPort}/application`,
method: 'GET',
headers: {
authorization: `${authConf.secret}`
}
}
return new Promise(function (resolve, reject) {
request(options, function (error, res, body) {
if (!error && res.statusCode == 200) {
const srs = JSON.parse(body);
const response = srs['response'];
for(let i =0;i < response.length;i++){
const { id, info } = response[i];
var status = "";
var issueId = "";
var statusClass = "";
for(let x = 0; x < info.length; x++){
if(info[x].key === "status"){
status = info[x].value;
statusClass = info[x].valueClass;
}
if(info[x].key === applicationConf.fields.issueId){
issueId = info[x].value;
}
}
if(statusClass === 0){
if(issueId !== null && issueId !== ""){
serviceRecords.push({id, status, issueId});
}
}
}
//console.log(serviceRecords);
resolve(serviceRecords);
} else {
//console.log(error);
reject(error);
}
});
});
},
getIssues : async (issueId) => {
issueRecords = [];
return new Promise(function(resolve, reject) {
var options = {
url: `http://localhost:${authConf.serverPort}/application2/${issueId}`,
method: 'GET',
headers: {
authorization: `${authConf.secret}`
}
}
request(options, function(error, res, body) {
if (!error && res.statusCode == 200) {
const issues = JSON.parse(body);
const { issue } = issues.response;
const { id, status, custom_fields } = issue;
issueRecords.push({id, status, custom_fields});
resolve(issueRecords);
} else {
reject(error);
}
});
});
},
sync : async () => {
return new Promise(function(resolve, reject) {
for (let i = 0; i < serviceRecords.length; i++) {
const application_id = serviceRecords[i].id;
const application_status = serviceRecords[i].status;
const application_issueId = serviceRecords[i].issueId;
//console.log('issueRecords.length: ', issueRecords);
//console.log('issueRecords.length: ', issueRecords.length);
console.log(`********** application`);
console.log(`└─ id ${application_id}`);
console.log(`└─ status ${application_status}`);
console.log(`└─ issueId ${application_issueId}`);
var application2 = await SchedulerService().getIssues(application_issueId)
.then(response => {
resolve(() => {
console.log(`i've found a record by issue_id ${application_issueId}`);
});
}).catch(error => {
reject(error);
});
}
});
}
}
}
export default new SchedulerService();
Thank you so much!
If you had getIssues resolve with issueId and issueRecords you might do something like this in sync:
sync: async () => {
// `map` over the serviceRecords and return a getIssues promise for each issueId
const promises = serviceRecords.map(({ issueId }) => SchedulerService().getIssues(issueId));
// Wait for all the promises to resolve
const data = await Promise.all(promises);
// Loop over the resolved promises and log the issueId
data.forEach((issueId, issueRecords) => console.log(issueId));
}

Nested async queries

//express is the framework we're going to use to handle requests
const express = require('express');
//Create a new instance of express
const app = express();
const FormData = require("form-data");
const bodyParser = require("body-parser");
const http = require('http');
const async = require('async');
//This allows parsing of the body of POST requests, that are encoded in JSON
app.use(bodyParser.json());
var router = express.Router();
//AccuWeather API key
const weatherKey = process.env.WEATHER_KEY_TWO;
cityCode = ""; //City code
cityName = "";
//Current Conditions Vars
var ccWeatherText = ""; //Text for weather at location
var ccTemp = 0; //Degrees Farenheit
var ccIcon = 0; //weather icon number https://developer.accuweather.com/weather-icons
var ccURL = "test"; //URL for get
var hourlyData = [];
var fiveDayData = [];
router.post('/', (req, res) => {
let lat = req.body['lat'];
let lon = req.body['lon'];
var latLongCityCodeURL = ("http://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=" + weatherKey + "&q=" + lat + "," + lon);
//Get city code
const httpGet = url => {
return new Promise((resolve, reject) => {
http.get(url, res => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
try {
body = JSON.parse(body);
} catch (err) {
reject(new Error(err));
}
resolve({
code: body.Key,
name: body.EnglishName
});
});
}).on('error', reject);
});
};
//Current Conditions
const ccGet = url => {
return new Promise((resolve, reject) => {
http.get(url, res => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
try {
body = JSON.parse(body);
} catch (err) {
reject(new Error(err));
}
resolve({
text: body[0].WeatherText,
temp: body[0].Temperature.Imperial.Value,
icon: body[0].WeatherIcon
});
});
}).on('error', reject);
});
};
//12 hour
const twelveGet = url => {
return new Promise((resolve, reject) => {
http.get(url, res => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
try {
body = JSON.parse(body);
} catch (err) {
reject(new Error(err));
}
resolve({
body: body
});
});
}).on('error', reject);
});
};
//5 day
const fiveGet = url => {
return new Promise((resolve, reject) => {
http.get(url, res => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
try {
body = JSON.parse(body);
} catch (err) {
reject(new Error(err));
}
resolve({
body: body
});
});
}).on('error', reject);
});
};
//Get city code from lat lon
httpGet(latLongCityCodeURL).then(data => {
cityCode = data.code;
cityName = data.name;
ccURL = ("http://dataservice.accuweather.com/currentconditions/v1/" + cityCode + "?apikey=" + weatherKey);
twelveURL = ("http://dataservice.accuweather.com/forecasts/v1/hourly/12hour/" + cityCode + "?apikey=" + weatherKey);
fiveURL = ("http://dataservice.accuweather.com/forecasts/v1/daily/5day/" + cityCode + "?apikey=" + weatherKey);
//Get Current Conditions
ccGet(ccURL).then(dataCC => {
ccTemp = dataCC.temp;
ccWeatherText = dataCC.text;
ccIcon = dataCC.icon;
//Get 12 hour forecast
twelveGet(twelveURL).then(dataTwelve => {
//Generate hourly data
for (i = 0; i < dataTwelve.length; i++) {
hourlyData[i] = {
time: dataTwelve[i].EpochDateTime,
temp: dataTwelve[i].Temperature.Value,
text: dataTwelve[i].IconPhrase,
icon: dataTwelve[i].WeatherIcon
};
}
console.log("Hourly Data: " + hourlyData);
}).catch(err => console.log(err));
fiveGet(fiveURL).then(dataFive => {
//Generate five day data
for (i = 0; i < dataFive.length; i++) {
fiveDayData[i] = {
time: dataFive[i].EpochDate,
min: dataFive[i].Temperature.Minimum.Value,
max: dataFive[i].Temperature.Maximum.Value,
iconDay: dataFive[i].Day.Icon,
iconNight: dataFive[i].Night.Icon,
dayPhrase: dataFive[i].Day.IconPhrase,
nightPhrase: dataFive[i].Night.IconPhrase
};
console.log("5 Day Data:" + fiveDayData);
}
res.send({
success: true,
cityName: cityName,
cityCode: cityCode,
currentConditions: {
temp: ccTemp,
icon: ccIcon,
text: ccWeatherText
},
hourlyData: hourlyData,
fiveDayData: fiveDayData
});
}).catch(err => console.log(err));
}).catch(err => console.log(err));
}).catch(err => console.log('Got error ', err));
});
module.exports = router;
Ok so right now I'm creating an endpoint in NodeJS that is POST method which gets the arguments for latitude and longitude. When it gets those it makes calls to Accuweather's API. I got all the accuweather stuff working and returning proper results, but then I cut and pasted that code into my POST method router.post... and now it isn't working. I know it is an ASYNC issue, and I am just getting really lost with async, since I have like 3 or 4 nested async calls inside the router.post, which is another async call. So I'm thinking there is some way to maybe wrap the router.post into its own async call, which waits on the weather calls before returning results?
My end goal: For the user to send a POST with lat and lon, my code does all the weather calls, and returns the data for the POST.
What you want to do is called promise chaining:
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
}).then(function(result) { // (***)
alert(result); // 2
return result * 2;
}).then(function(result) {
alert(result); // 4
return result * 2;
});
Also, check out MDN's page on using promises

Categories

Resources