nodejs async await all data in one variable - node.js

I want to check If a Domain is on spam list.
const dnsbl = require('dnsbl');
const spam1 = await dnsbl.lookup('127.0.0.2', 'zen.spamhaus.org');
const spam2 = await dnsbl.lookup('127.0.0.2', 'zen.spamhaus.org', {includeTxt: true});
const spam3 = ...
I want to check 30 Spamsite. Do I have to make now 30 variables like spam4, spam5, spam6? Or is there a more efficient way to do it?
And how do I save all the results that are found in a variable?

The following code executes all 30 methods in parallel, and returns you (only if all the 30 promises executed successfuly) the 30 results.
const dnsbl = require('dnsbl');
(async () => {
const promiseArr = [
dnsbl.lookup('127.0.0.2', 'zen.spamhaus.org'),
dnsbl.lookup('127.0.0.2', 'zen.spamhaus.org'),
dnsbl.lookup('127.0.0.2', 'zen.spamhaus.org'),
dnsbl.lookup('127.0.0.2', 'zen.spamhaus.org'),
...,
...,
];
let results;
try {
results = await Promise.all(promiseArr);
} catch (e) {
console.log(e);
}
})();

Related

Facing issue with scooping in node JS

This code is showing empty object ( {} )
// declared at top
let mainData = {};
let trainStations = {};
let routes = {};
let trainNo = {};
data["data"].forEach(async (element) => {
const response2 = await fetch(
`https://india-rail.herokuapp.com/trains/getRoute?trainNo=${element["train_base"]["train_no"]}`
);
const data2 = await response2.json();
data2["data"].forEach((ele) => {
routes[ele["source_stn_code"]] = true;
});
trainNo[element["train_base"]["train_no"]] = routes;
});
console.log(trainNo);
if i do this then i will give response with data
data["data"].forEach(async (element) => {
const response2 = await fetch(
`https://india-rail.herokuapp.com/trains/getRoute?trainNo=${element["train_base"]["train_no"]}`
);
const data2 = await response2.json();
data2["data"].forEach((ele) => {
routes[ele["source_stn_code"]] = true;
});
trainNo[element["train_base"]["train_no"]] = routes;
console.log(trainNo);
});
maybe there is some scooping issue please kindly help me to solve this problem :)
Please refer here and also check this.
As a short note, using await inside a forEach() loop will give unexpected results. This is because the forEach() does not wait until the promise to settled (either fulfilled or rejected).
A simple solution for this could be using either the traditional for loop or the for..of loop.
for(let element of data["data"]){
const response2 = await fetch(
`https://india-rail.herokuapp.com/trains/getRoute?trainNo=${element["train_base"]["train_no"]}`
);
const data2 = await response2.json();
data2["data"].forEach((ele) => {
routes[ele["source_stn_code"]] = true;
});
trainNo[element["train_base"]["train_no"]] = routes;
}
console.log(trainNo);
NOTE: Make sure to wrap the above for..of loop inside an async function because the await keyword is allowed inside a function only when the function is defined with async keyword.

fs.watchFile() a json file until a specific value appear

So I have a json file that changes continously and I need to read it AFTER a value called auth-token is written to the file, here what I get now:
const json = fs.readFileSync("some-json.json")
const headers = JSON.parse(json);
return headers
But it reads the file before anything can be written to it, is there anyway that I can use fs.watchFile() and watch the file UNTIL the value is written?
Thanks
You can use fs.watch although its behavior is a bit unreliable with multiple events triggered upon file change (but I don't think it would be a problem here).
Here is a small sample:
const { watch } = require('fs');
const { readFile } = require('fs/promises');
(async () => {
const result = await new Promise((resolve) => {
const watcher = watch('some-json.json', async (eventType, filename) => {
try {
const fileContent = await readFile(filename);
const headers = JSON.parse(fileContent.toString());
if (headers['auth-token']) { // or whatever test you need here
watcher.close();
resolve(headers);
}
} catch (e) {}
});
});
console.log(result);
})();
Note that if your file gets modified many times before it contains the desired header, it might be preferable to replace the usage of fs.watch by a setInterval to read the file at regular intervals until it contains the value you expect.
Here is what it would look like:
const { readFile } = require('fs/promises');
(async () => {
const waitingTime = 1000;
const result = await new Promise((resolve) => {
const interval = setInterval(async (eventType, filename) => {
const fileContent = await readFile('some-json.json');
try {
const headers = JSON.parse(fileContent.toString());
if (headers['auth-token']) { // or whatever test you need here
clearInterval(interval);
resolve(headers);
}
} catch (e) {}
}, waitingTime);
});
console.log(result);
})();

Jest functions export

I'm using jest+puppeteer and I have a code that I'd like to reuse across my project.
I use the following instruction:
https://jestjs.io/docs/en/getting-started
//adminLogin2.js
const admLog = function admLog () {
return
page.goto(data.config.env.host);
page.waitForSelector(data.selectors.admin.auth.input_login);
page.click(data.selectors.admin.auth.input_login);
page.type(data.selectors.admin.auth.input_login, data.credentials.business_email.login);
page.click(data.selectors.admin.auth.form_button_first);
// second step
page.waitForSelector(data.selectors.admin.auth.input_login_password);
page.click(data.selectors.admin.auth.input_login_password);
page.type(data.selectors.admin.auth.input_login_password, data.credentials.business_email.password);
page.click(data.selectors.admin.auth.form_button_second);
page.waitForSelector(data.selectors.admin.auth.business_login_button);
page.click(data.selectors.admin.auth.business_login_button);
page.waitForSelector(data.selectors.admin.auth.business_body);
}
module.exports = admLog;
//test
const data = require('../config');
const admLog = require('../struct/Login/adminLogin2');
describe('GetPackage :: Auth', () => {
it('Admin Email', async () => {
await admLog();
});
});
Test could be run without exceptions, but nothing happens, in headless:false mode Chrome is just run and closed.
What should be fixed?
Add the async/await in the admLog function.
Remove the return statement to prevent the Automatic semicolon insertion
So the final adminLogin2.js file should be like this:
//adminLogin2.js
const admLog = async function() {
await page.goto(data.config.env.host);
await page.waitForSelector(data.selectors.admin.auth.input_login);
await page.click(data.selectors.admin.auth.input_login);
await page.type(data.selectors.admin.auth.input_login, data.credentials.business_email.login);
await page.click(data.selectors.admin.auth.form_button_first);
// second step
await page.waitForSelector(data.selectors.admin.auth.input_login_password);
await page.click(data.selectors.admin.auth.input_login_password);
await page.type(data.selectors.admin.auth.input_login_password, data.credentials.business_email.password);
await page.click(data.selectors.admin.auth.form_button_second);
await page.waitForSelector(data.selectors.admin.auth.business_login_button);
await page.click(data.selectors.admin.auth.business_login_button);
await page.waitForSelector(data.selectors.admin.auth.business_body);
}
module.exports = admLog;

pool.request is not a function

I would like to setup my prepared statements with the mssql module. I created a query file for all user related requests.
const db = require('../databaseManager.js');
module.exports = {
getUserByName: async username => db(async pool => await pool.request()
.input('username', dataTypes.VarChar, username)
.query(`SELECT
*
FROM
person
WHERE
username = #username;`))
};
This approach allows me to require this query file and access the database by executing the query that is needed
const userQueries = require('../database/queries/users.js');
const userQueryResult = await userQueries.getUserByName(username); // call this somewhere in an async function
My database manager handles the database connection and executes the query
const sql = require('mssql');
const config = require('../config/database.js');
const pool = new sql.ConnectionPool(config).connect();
module.exports = async request => {
try {
const result = await request(pool);
return {
result: result.recordSet,
err: null
};
} catch (err) {
return {
result: null,
err
}
}
};
When I run the code I get the following error
UnhandledPromiseRejectionWarning: TypeError: pool.request is not a
function
Does someone know what is wrong with the code?
I think this happens because the pool is not initialized yet... but I used async/await to handle this...
Here is how I made your code work (I did some drastic simplifications):
const sql = require("mssql");
const { TYPES } = require("mssql");
const CONN = "";
(async () => {
const pool = new sql.ConnectionPool(CONN);
const poolConnect = pool.connect();
const getUserByName = async username => {
await poolConnect;
try {
const result = await pool.request()
.input("username", TYPES.VarChar, username)
.query(`SELECT
*
FROM
person
WHERE
username = #username;`);
return {
result: result.recordset,
err: null
};
} catch (err) {
return {
result: null,
err
};
}
};
console.log(await getUserByName("Timur"));
})();
In short, first read this.
You probably smiled when saw that the PR was created just 2 months before your questions and still not reflected in here.
Basically, instead of:
const pool = new sql.ConnectionPool(config).connect();
you do this:
const pool = new sql.ConnectionPool(config);
const poolConnection = pool.connect();
//later, when you need the connection you make the Promise resolve
await poolConnection;

node.js Get.Request & Pagination & Async

I'm having a tremendously tough time organizing the flow here as I'm self-taught so wondering if someone might be able to assist.
var channelIds = ['XYZ','ABC','QRS']
var playlistIds = [];
var videoIds = [];
ORDER OF PROCESS
1. Get All Playlist IDs: If returning Get Request JSON contains nextPageToken run Get Request again with that page before going to (2)
2. Get All Video IDs: If returning Get Request JSON contains nextPageToken run Get Request again with that page before going to (3)
3. Aggregate into Final Array: I need put all in an array such as:
var ArrFinal = [{channelId,playlistID,videoId},{channelId,playlistID,videoId},{channelId,playlistID,videoId}];
I don't necessarily need someone to write the whole thing. I'm trying to better understand the most efficient way to know when the previous step is done, but also handle the nextPageToken iteration.
i'm not familiar with the youtube api.
But what you basically need is a get function for each endpoint. This function should also care about the "nextPageToken".
Something like that: (not tested)
'use strict';
const Promise = require('bluebird');
const request = Promise.promisifyAll(require('request'));
const playlistEndpoint = '/youtube/v3/playlists';
const baseUrl = 'https://www.googleapis.com'
const channelIds = ['xy', 'ab', 'cd'];
const getPlaylist = async (channelId, pageToken, playlists) => {
const url = `${baseUrl}${playlistEndpoint}`;
const qs = { 
channelId,
maxResults: 25,
pageToken
};
try {
const playlistRequest = await request.getAsync({ url, qs });
const nextPageToken = playlistRequest.body.nextPageToken;
// if we already had items, combine with the new ones
const items = playlists ? playlists.concat(playlistRequest.body.items) : playlistRequest.body.items;
if (nextPageToken) {
// if token, do the same again and pass results to function
return getPlaylist(channelId, nextPageToken, items);
}
// if no token we are finished
return items;
}
catch (e) {
console.log(e.message);
}
};
const getVideos = async (playlistId, pageToken, videos) => {
// pretty much the same as above
}
function awesome(channelIds) {
const fancyArray = [];
await Promise.map(channelIds, async (channelId) => {
const playlists = await getPlaylist(channelId);
const videos = await Promise.map(playlists, async (playlistId) => {
const videos = await getVideos(playlistId);
videos.forEach(videoId => {
fancyArray.push({ channelId, playlistId, videoId })
})
});
});
return fancyArray;
}
awesome(channelIds)
// UPDATE
This may be a lot concurrent requests, you can limit them by using
Promise.map(items, item => { somefunction() }, { concurrency: 5 });

Resources