Refactoring JavaScript, shortening variable declaration - javascript

I have the following code that works as expected:
(async () => {
const first = document.getElementById("first"), second = document.getElementById("second");
try {
first.innerHTML = await (await fetch('https://myAPI.com/1')).text();
second.innerHTML = await (await fetch('https://myAPI.com/2')).text();
} catch {
first.innerHTML = 'Error';
second.innerHTML = 'Error';
}
})();
But I am curious whether there is a way to shorten the declaration of my variables, something like this (which doesn't work):
(async () => {
const [first, second] = document.getElementById("[first, second]");
try {
first.innerHTML = await (await fetch('https://myAPI.com/1')).text();
second.innerHTML = await (await fetch('https://myAPI.com/2')).text();
} catch {
first.innerHTML = 'Error';
second.innerHTML = 'Error';
}
})();
Just curious as to whether I can get rid of that second appearance of 'document.getElementById' to make the line more compact.

The most concise way to do it is by using the following:
const [first, second] = document.querySelectorAll("#first, #second");

Related

Calling an asynchronous function, main thread wont stop and then there is result with undefined

I am trying to improve my skills with async, await. So I am trying to make an app that collects the prices of different flights in different periods and then it decides in which period the plane ticket is cheapest for personal use.
const puppeteerExtra = require("puppeteer-extra");
const pluginStealth = require("puppeteer-extra-plugin-stealth");
puppeteerExtra.use(pluginStealth());
const PCR = require("puppeteer-chromium-resolver");
const howLongStart = 7;
const howLongEnd = 8;
const fromDate = new Date("2023-07-15");
const toDate = new Date("2023-08-31");
const airport = "PDL";
let tickets = [];
for (let i = 0; i < howLongEnd - howLongStart; i++) {
let howLong = howLongStart + i;
let tempFromDate = new Date("2023-07-15");
let tempFromD = new Date("2023-07-15");
let tempToDate = addDays(tempFromD, howLong);
async function ticketFirstMethod() {
const ticketFirst = await searchFlight(airport, tempFromDate, tempToDate);
tickets.push(ticketFirst);
}
ticketFirstMethod();
while (addDays(tempToDate, 1) <= toDate) {
tempFromDate = addDays(tempFromDate, 1);
tempToDate = addDays(tempToDate, 1);
async function ticketMethod() {
let ticket = await searchFlight(airport, tempFromDate, tempToDate);
tickets.push(ticket);
}
ticketMethod();
}
}
let lowestTicket;
let lowest = Number.POSITIVE_INFINITY;
let highest = Number.NEGATIVE_INFINITY;
let tmp;
for (let i = tickets.length - 1; i >= 0; i--) {
tmp = tickets[i][0];
if (tmp < lowest) {
lowest = tmp;
lowestTicket = tickets[i];
}
if (tmp > highest) highest = tmp;
}
console.log(lowestTicket);
function addDays(date, days) {
date.setDate(date.getDate() + days);
return date;
}
async function searchFlight(airport, tempFromDate, tempToDate) {
const stats = await PCR();
const browser = await puppeteerExtra.launch({
executablePath: stats.executablePath,
headless: false,
});
const page = await browser.newPage();
await page.goto(
"https://www.pelikan.cz/cs/letenky/T:1,P:4000E_0_0,CDF:PRGMUCFRATXLVIE,CDT:C" +
airport +
",R:1,DD:" +
tempFromDate.getFullYear +
"_" +
tempFromDate.getMonth +
"_" +
tempFromDate.getDay +
",DR:" +
tempToDate.getFullYear +
"_" +
tempToDate.getMonth +
"_" +
tempToDate.getDay +
"/",
{ waitUntil: "networkidle2", timeout: 0 }
);
const cheapestPrice = await page.waitForSelector(
"#flight-10000 > div:nth-child(1) > flights-flight:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(2) > div:nth-child(1) > div:nth-child(1) > div:nth-child(3)"
);
const price = await page.evaluate((el) => el.textContent, cheapestPrice);
const priceOnly = price.replace(/\D/g, "");
const ticket = [priceOnly, page.url()];
await browser.close();
return ticket;
}
I have tried to put here an example of the code.
Can anyone please help me?
EXPECTED
Firstly I choose a period from when to when it should be searching for the ticket. Then I call searchFlight with this period of time to search for the ticket. The main thread will wait for the function to be processed and then the ticket is pushed to tickets.
BEHAVIOUR
The main thread will not wait and it continous so there is undefined ticket pushed to tickets.
I was trying to use the then method on the line where I am calling searchFlight function. In then method I put tickets.push(ticket). But that didn't work.
I was trying to search for fix but because I dont understand await, async that much I could not fix my code.
First off, remove the (async () => { .... }() wrapper. That's superfluous and getting in the way. The parent function is already async so the wrapper is not needed.
Then, searchFlight is async so you need to await its result where you are calling it. And, you'll need to make it's parent function async so you can use that await.
const ticket = await searchFlight(airport, tempFromDate, tempToDate);
Then, you have to actually return a result from inside of searchFlight. Right now, you have no return result at the top level of that function.
I would suggest you do that by not mixing await and .then(). Just use await like this:
async function searchFlight(airport, tempFromDate, tempToDate){
const stats = await PCR();
const browser = await puppeteerExtra.launch({
executablePath: stats.executablePath,
headless: false
});
const page = await browser.newPage()
await page.goto("...", {waitUntil: "networkidle2", timeout: 0})
const cheapestPrice = await page.waitForSelector('...');
const price = await page.evaluate(el => el.textContent, cheapestPrice);
const priceOnly = price.replace(/\D/g, "");
const ticket = [priceOnly, page.url()];
await browser.close()
return ticket;
}
And, please eliminate any use of var. One should only be using const or let in modern Javascript.

how to get dynamic id by using selenium and JavaScript

I want to take all id from this page by using JavaScript.
const webdriver = require('selenium-webdriver');
const {Build, By, Key, until} = webdriver;
(async function getDiv () {
let driver = new webdriver.Builder().forBrowser('chrome').build();
try {
await driver.get('https://www.scoresandodds.com/nba');
await driver.sleep(1000);
var ids = driver.getElementsByName('id')
console.log("----");
//for (let elm of (await div)) {
// console.log(`${elm}`); }
console.log(`${ids}`);
}
catch(error) {
console.error(error);
}
finally {
if (driver) {
await driver.quit();
}
}
})();
its error, could you teach me why I canot get them?
Thank you.
I got this.
let webdriver = require('selenium-webdriver');
let chrome = require('selenium-webdriver/chrome');
let By = webdriver.By;
let map = webdriver.promise.map;
(async () => {
var driver = await new webdriver.Builder()
.withCapabilities(webdriver.Capabilities.chrome())
.setChromeService(new chrome.ServiceBuilder(
"C:chromedriver.exe")
)
.build();
await driver.get("https://www.scoresandodds.com/nba");
var elements = await driver.findElements(By.xpath("//*[#class='event-card']"));
var vals = await map(elements, element => element.getAttribute('id')).then();
vals.forEach(val => console.log(val));
await driver.quit();
})();

How do I remove a specific custom conditional format from all ranges that use it? I am using the delete() method, but that doesn't work

When I apply the conditional formats, I store it in the conditionalFormatCols and conditionalFormatRows variables. I then use the delete() method on these variables, but this doesn't delete the conditional formatting on the cells. How do I delete conditional formatting so it no longer shows up in the workbook?
let eventResult;
let navAidIsOn = false;
let conditionalFormatCols;
let conditionalFormatRows;
async function navAid() {
await Excel.run(async (context) => {
if (!navAidIsOn) {
applyConditionalFormatting();
const sheet = context.workbook.worksheets.getActiveWorksheet();
eventResult = sheet.onSelectionChanged.add(navAidListener);
navAidIsOn = !navAidIsOn;
} else {
turnNavAidOff();
}
});
}
async function turnNavAidOff(){
await Excel.run(eventResult.context ,async (context) => {
eventResult.remove()
Here I try to use the delete() method
conditionalFormatCols.delete();
conditionalFormatRows.delete();
await context.sync();
navAidIsOn = !navAidIsOn;
});
}
async function navAidListener() {
applyConditionalFormatting();
}
async function applyConditionalFormatting() {
await Excel.run(async (context) => {
const sheet = context.workbook.worksheets.getActiveWorksheet();
let ranges;
let rangeArray = [];
await context.sync();
let columns;
let rows;
ranges = context.workbook.getSelectedRanges();
await context.sync();
ranges.load("address");
await context.sync();
let rangeStrs = ranges.address.split(",");
rangeStrs.forEach((rangeStr) => {
rangeArray.push(sheet.getRange(rangeStr).load("columnIndex, rowIndex, rowCount, columnCount"));
});
await context.sync();
rangeArray.forEach(async (range) => {
columns = sheet.getRangeByIndexes(0, range.columnIndex, 1048576, range.columnCount);
rows = sheet.getRangeByIndexes(range.rowIndex, 0, range.rowCount, 16384);
await context.sync();
conditionalFormatCols = columns.conditionalFormats.add(Excel.ConditionalFormatType.custom);
conditionalFormatCols.custom.rule.formula = "TRUE";
conditionalFormatCols.custom.format.fill.color = "#D2F0E0";
conditionalFormatRows = rows.conditionalFormats.add(Excel.ConditionalFormatType.custom);
conditionalFormatRows.custom.rule.formula = "TRUE";
conditionalFormatRows.custom.format.fill.color = "#D2F0E0";
await context.sync();
});
});
}

Node Js - SyntaxError: await is only valid in async function

I have below code in service.js file.
exports.getSeminarDetailsById = async function (seminarId) {
try {
let SeminarList = [];
var seminarData = await SeminarRepository.getSeminarDetailsById(seminarId);
if (seminarData && seminarData.length > 0) {
let userIdList = [...new Set(seminarData.map(x => x.user_id))];
if (userIdList && userIdList.length > 0) {
let userDetails = await EmployeeRepository.getEmployeeDetailsByUserIds(userIdList);
if (userDetails && userDetails.length > 0) {
seminarData.forEach(element => {
let seminarDetail;
let userName = userDetails.filter(x => x.user_id == element.user_id).map(x => x.userfullname)[0];
let categoryName;
if (element.category_id == 1)
categoryName = AppConstants.seminarCategoryName.TECHNICAL;
else
categoryName = AppConstants.seminarCategoryName.NONTECHNICAL;
seminarDetail = new SeminarTrackerDetails(element, userName, categoryName);
await mapAttachmentWithSeminar(seminarId, seminarDetail);
console.log("second", seminarDetail);
SeminarList.push(seminarDetail);
});
}
}
}
return SeminarList;
} catch (err) {
console.log(err);
throw err;
}
}
Here error comes on await mapAttachmentWithSeminar(seminarId, seminarDetail); and it is defined in the same file as below.
async function mapAttachmentWithSeminar(seminarId, seminarDetail) {
var seminarAttachmentDetails = await SeminarRepository.getSeminarAttachmentDetailsById(seminarId);
if (seminarAttachmentDetails && seminarAttachmentDetails.length > 0) {
let AttachmentDetails = [];
seminarAttachmentDetails.forEach(element => {
let attachmentDetails = new SeminarAttachmentDetails(element);
AttachmentDetails.push(attachmentDetails);
});
seminarDetail.SeminarAttachmentDetails = AttachmentDetails;
}
else {
seminarDetail.SeminarAttachmentDetails = null;
console.log("first", seminarDetail);
}
}
If I remove the await function, then console.log("second", seminarDetail); will be executed first before executing the function mapAttachmentWithSeminar(). So that the value of SeminarAttachmentDetails returning from that function will be missed as shown below:
This was the expected output.
Instead of using .forEach you could go with a classic for loop
for(let i = 0; i < seminarData.length; i++){
let element = seminarData[i];
let seminarDetail;
let userName = userDetails.filter(x => x.user_id == element.user_id).map(x => x.userfullname)[0];
let categoryName;
if (element.category_id == 1)
categoryName = AppConstants.seminarCategoryName.TECHNICAL;
else
categoryName = AppConstants.seminarCategoryName.NONTECHNICAL;
seminarDetail = new SeminarTrackerDetails(element, userName, categoryName);
await mapAttachmentWithSeminar(seminarId, seminarDetail);
console.log("second", seminarDetail);
SeminarList.push(seminarDetail);
}
First you are using wrong async await. You are awaiting inside the scope of a function which is not async.
Here:
seminarData.forEach(element => {
let seminarDetail;
let userName = userDetails.filter(x => x.user_id == element.user_id).map(x => x.userfullname)[0];
let categoryName;
if (element.category_id == 1)
categoryName = AppConstants.seminarCategoryName.TECHNICAL;
else
categoryName = AppConstants.seminarCategoryName.NONTECHNICAL;
seminarDetail = new SeminarTrackerDetails(element, userName, categoryName);
await mapAttachmentWithSeminar(seminarId, seminarDetail);
console.log("second", seminarDetail);
SeminarList.push(seminarDetail);
});
You should have this
// here you have the SeminarList but promisified
// with the form Promise<SeminarListItem>[]
// to get the values out of the promises you have to await this array
const promisifiedSeminarList = seminarData.map((element)=>{
let userName = userDetails.filter(x => x.user_id == element.user_id).map(
x => x.userfullname)[0]
);
const categoryName = elemenet.category_id == 1
? AppConstants.seminarCategoryName.TECHNICAL
: AppConstants.seminarCategoryName.NONTTECHNICAL;
const seminarDetail = new SeminarTrackerDetails(element, userName, categoryName);
return mapAttachmentWithSeminar(seminarId, seminarDetail);
});
// now
const seminarList = await Promise.all(promisifiedSeminarList);
For that to work you need that the function mapAttachmentWithSemniar returns a value which is not happening
every nested function should be declared as async as well as parent's.
in your case this declaration is missed in one of nesting level, pay attention on this part of code
seminarData.forEach(async element => {
// ^^^^ async missed here
let seminarDetail;
let userName = userDetails.filter(x => x.user_id == element.user_id).map(x => x.userfullname)[0];
let categoryName;
if (element.category_id == 1)
categoryName = AppConstants.seminarCategoryName.TECHNICAL;
else
categoryName = AppConstants.seminarCategoryName.NONTECHNICAL;
seminarDetail = new SeminarTrackerDetails(element, userName, categoryName);
await mapAttachmentWithSeminar(seminarId, seminarDetail);
console.log("second", seminarDetail);
SeminarList.push(seminarDetail);
});

Pagination in Zapier

I am trying following code to get all records from a paginated API in Zapier.
const limitPerPage = 20;
const apiUrl = "https://myurl.com/data";
var lastCursor = null;
var output = null;
const getContent = async function (cursor) {
let actualUrl = apiUrl + `?cursor=${cursor}&limit=${limitPerPage}`;
var apiResults = await fetch(actualUrl)
.then(resp => {
return resp.json;
});
}
const getEntireContentList = async function (cursor) {
const results = await getContent(cursor);
console.log("Retreiving data from API for cursor : " + cursor);
if (results.metadata.cursor !== "") {
return results.concat(await getEntireContentList(results.metadata.cursor));
} else {
return results;
}
};
(async() => {
const entireList = await getEntireContentList();
console.log(entireList);
output = entireList;
callback(null, entireList);
})();
I get error as
You did not define output! Try output = {id: 1, hello: await Promise.resolve("world")};
How can I fix this?
Your problem is that though you're awaiting in that function, the top-level carries on and execution ends before your code has had a chance to run.
The good news is, Zapier wraps your code in an async function already, so you can use await at the top level (per these docs).
Try this instead:
const limitPerPage = 20;
const apiUrl = "https://myurl.com/data";
let lastCursor = null;
// var output = null; // zapier does this for you already
const getContent = async function (cursor) {
const actualUrl = apiUrl + `?cursor=${cursor}&limit=${limitPerPage}`;
const rawResponse = await fetch(actualUrl)
return resp.json() // async function, you had it as a property
}
const getEntireContentList = async function (cursor) {
const results = await getContent(cursor);
console.log("Retreiving data from API for cursor : " + cursor);
if (results.metadata.cursor !== "") {
return results.concat(await getEntireUserList(results.metadata.cursor)); // should this be named getEntireContentList?
} else {
return results;
}
};
return {
results: await getEntireContentList()
}
I noticed this is a recursive approach. That's fine, but remember that you've got limited execution time. You also might hit memory limits (depending on how many objects you're returning), so keep an eye on that.

Categories

Resources