Node async await code writing style which one is good and optimized - node.js

I used to write code for async-await in (Style 1), other dev suggested me to write in (Style 2).
Can someone please explain to me what is the difference between both styles, for me it seems the same.
Code Style 1:
const fixtures = await fixtureModel.fetchAll();
const team = await teamModel.fetch(teamId);
Code Style 2:
const fixturesPromise = fixtureModel.fetchAll();
const teamPromise = teamModel.fetch(teamId);
const fixtures = await fixturesPromise;
const team = await teamPromise;

They are not the same.
The first will initialize a Promise, wait for it to complete, then initialize another Promise, and wait for the second Promise to complete.
The second will initialize both Promises at once and wait for both to complete. So, it will take less time. Here's a similar example:
// Takes twice as long as the other:
const makeProm = () => new Promise(resolve => setTimeout(resolve, 1000));
console.log('start');
(async () => {
const foo = await makeProm();
const bar = await makeProm();
console.log('done');
})();
// Takes half as long as the other:
const makeProm = () => new Promise(resolve => setTimeout(resolve, 1000));
console.log('start');
(async () => {
const fooProm = makeProm();
const barProm = makeProm();
const foo = await fooProm;
const bar = await barProm;
console.log('done');
})();
But you might consider making the code even clearer with Promise.all instead:
const [fixtures, team] = await Promise.all([
fixtureModel.fetchAll(),
teamModel.fetch(teamId)
]);

Related

How to concurrency promise limit to specific number?

In my code, the executing promise is 1 by 1. its not concurrency concept. how to convert to concurrency with limit 8 promise. so its like a create a pool with limit 8 promise. then, push and read promise output realtime.
example.
if in 1 second it can done 2 promise job, then it will output 2 promise. and fill again the pool with 2 new promise job.
i dont want it wait 8 promise job done in sametime, and start to fill pool with 8 job again.
import fetch from 'node-fetch';
import { load } from 'cheerio';
(async () => {
const response = await fetch('https://hentairead.com/page/1/');
const $ = load(await response.text());
const totalPage = $('span.pages')
.text()
.match(/\d{3,}/g)
.toString();
for(let page = 1; page <= totalPage; page++)
{
const response = await fetch(`https://hentairead.com/page/${page}/`);
const $ = load(await response.text());
$('div.item-thumb.c-image-hover > a').each((index, item) => {
console.log(item.attribs.title);
});
}
})();
import fetch from 'node-fetch';
import { load } from 'cheerio';
import {CPromise} from "c-promise2";
(async () => {
const response = await fetch('https://hentairead.com/page/1/');
const $ = load(await response.text());
const totalPage = $('span.pages')
.text()
.match(/\d{3,}/g)
.toString();
const fetchPage= async (page)=>{
const response = await fetch(`https://hentairead.com/page/${page}/`);
const $ = load(await response.text());
$('div.item-thumb.c-image-hover > a').each((index, item) => {
console.log(item.attribs.title);
});
}
await CPromise.all(function*(){
for(let page = 1; page <= totalPage; page++){
yield fetchPage(page);
}
}, {concurrency: 8});
})();

nodejs async await all data in one variable

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);
}
})();

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;

nodejs How to fix `browser.newPage is not a function` using puppeteer-core?

I am trying to use pupetteer-core but when I run my code.
const puppeteer = require('puppeteer-core');
module.exports= run = () => {
const url = 'https://example.com'
const browser = puppeteer.launch();
const page = browser.newPage().then(function(page){
page.goto(url)
return browser
};
run().catch(console.error.bind(console))
I get this error
TypeError: browser.newPage is not a function
The problem in your code is that puppeteer works with Promises, meaning that most functions will return a Promise instead of the value directly. This means that you ether have to use then function or await statements to get the value.
Code sample
module.exports = run = async () => {
const url = 'https://example.com';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(url);
return browser;
};
Note that the function is marked as async now, making it implicitly returning a Promise. That means to wait for the run() function to finish, you would have to call it from within another async function like this:
(async () => {
const browser = await run();
})();

Get href attribute in pupeteer Node.js

I know the common methods such as evaluate for capturing the elements in puppeteer, but I am curious why I cannot get the href attribute in a JavaScript-like approach as
const page = await browser.newPage();
await page.goto('https://www.example.com');
let links = await page.$$('a');
for (let i = 0; i < links.length; i++) {
console.log(links[i].getAttribute('href'));
console.log(links[i].href);
}
await page.$$('a') returns an array with ElementHandles — these are objects with their own pupeteer-specific API, they have not usual DOM API for HTML elements or DOM nodes. So you need either retrieve attributes/properties in the browser context via page.evaluate() or use rather complicated ElementHandles API. This is an example with both ways:
'use strict';
const puppeteer = require('puppeteer');
(async function main() {
try {
const browser = await puppeteer.launch();
const [page] = await browser.pages();
await page.goto('https://example.org/');
// way 1
const hrefs1 = await page.evaluate(
() => Array.from(
document.querySelectorAll('a[href]'),
a => a.getAttribute('href')
)
);
// way 2
const elementHandles = await page.$$('a');
const propertyJsHandles = await Promise.all(
elementHandles.map(handle => handle.getProperty('href'))
);
const hrefs2 = await Promise.all(
propertyJsHandles.map(handle => handle.jsonValue())
);
console.log(hrefs1, hrefs2);
await browser.close();
} catch (err) {
console.error(err);
}
})();
const yourHref = await page.$eval('selector', anchor => anchor.getAttribute('href'));
but if are working with a handle you can
const handle = await page.$('selector');
const yourHref = await page.evaluate(anchor => anchor.getAttribute('href'), handle);
I don't know why it's such a pain, but this was found when I encountered this a while ago.
async function getHrefs(page, selector) {
return await page.$$eval(selector, anchors => [].map.call(anchors, a => a.href));
}
A Type safe way of returning an array of strings as the hrefs of the links by casting using the HTMLLinkElement generic for TypeScript users:
await page.$$eval('a', (anchors) => anchors.map((link) => (link as HTMLLinkElement).href));
A simple way to get an href from an anchor element
Say you fetched an anchor element with the following
const anchorElement = await page.$('a') // or page.$<HTMLAnchorElement>('a') if using typescript
You can get the href property with the following
const href = anchorElement.evaluate(element => element.href)

Resources