Can't assign API data from fetch to variable in function - javascript

I have a JS module that is a function that fetches Issue data from our company Github, that I then want assigned to a variable:
import { request } from "https://cdn.skypack.dev/#octokit/request";
let issueData
async function getIssues() {
const issueAPI = await request("GET repos/{owner}/{repo}/issues", {
baseUrl: "https://company.com/api/v3/",
owner: "me",
repo: "exampleRepo",
});
window.issueData = issueAPI.data
return issueAPI.data
}
export { getIssues, issueData }
I can't seem to get the issueAPI.data to assign to my variable issueData? What's going wrong here? I have a feeling it's something to do with the promises/async or scope but just can't work it out.

You are assigning issueAPI.data to a window variable called issueData, which is not the same variable that you have defined with let on your snippet. If you want to assign to your declared variable, you just need to do this.
let issueData = await getIssues()
If there are no other errors in the function, this should correctly assign what you want to your declared variable.
Also you can drop the window.issueData = issueAPI.data unless you really want to have that accesible from the window object.
EDIT: As Jeremy points out, this would require top-level await. A workaround also provided by Jeremy:
let issueData
( async () => { issueData = await getIssues() })()

Related

If a function is only used in another function should I keep it inside or outside it?

Like in the subject. I have a function like below and I have quite a bit of helping functions declared within a function (twice as much than in the example) because it's the only one using them.
My question is: should I extract those helping functions outside the function to maintain rule "Function should do one job and do it well" or it should be within? I also read about that higher level functions should be higher for better readability, but it somehow doesn't work (shouldn't hoisting make it work?).
const queryThings = async (body = defaultBody) => {
try {
(...)
// helping functions
const isNonTestDeal = obj => (...)
const isNonEmpty = obj => (...)
const replaceHTMLEntity = obj => (...)
const extractCountries = o => (...)
const queried = await query(...) // that one is outside this function
const cases = queriedCases
.filter(isNonTestDeal)
.map(obj => {
let countries = [(...)]
.filter(isNonEmpty)
.map(replaceHTMLEntity)
.map(extractCountries)
let data = {
(...)
}
return data
})
.filter(obj => (...))
.sort((a,b) => a.d - b.d)
.slice(0, 45) // node has problem with sending data of more than 8KB
return cases
} catch (error) {
console.log(error)
}
}
If you declare the function outside, and only use it in one function, then you cause namespace pollution. (What is namespace pollution?) Thus, I would recommend keeping it inside. Also, if you do so, it is easier to read as well, since it will be closer to the code where it is used.
To address your question about hoisting, it only works if you declare your function without assigning it to a variable.
i think when you write function in other function the memory use is better than write out of function
but you can't use in another function it is local function and it isn't public function

Getting page.evaluate not a function error

I created a helper to manage my code in my other module. I wrote this piece of code:
Scraper: async function(page, selector1, selector2, selector3) {
let list_of_items = await page.evaluate(() => {
let items = [];
let elemend = selector1
let items_present = document.querySelectorAll(elemend);
items_present.forEach((element) => {
let itemJson = {};
try {
itemJson.name = element.querySelector(selector2).innerText;
if(element.querySelector(selector3)){
itemJson.price = element.querySelector(selector3).innerText;
}
}
catch (exception){
}
items.push(itemJson);
});
return items;
});
console.dir(list_of_items);
Every time I try to execute my code it fails and says evaluate is not a function
await Scraper.Scraper(hunt.div_container, hunt.name_selector, hunt.price_selector);
You are calling it wrong, do not do call it as await Scraper.Scraper() call it like a normal function Scraper.Scraper() also maybe don't use the same name for the class and function as that can get confusing and will become a nightmare to debug in a not so distant time and lastly ensure that the class as been instantiated first, cause it seems to me that your automation tool is inside a class, so ensure you instantiate it first before calling functions inside of it

How to fix scope problem inside "then" function react?

I am trying to print out of Printer. I am a little new to react and javascript. I am trying to pass the state to a then function of Third Party Code. But i am getting an error:
Cannot read property 'restaurant_name' of undefined
How can i pass state to the scope of then function of qz?
print = () => {
let { state } = this.state;
qz.websocket.connect()
.then(function() {
return qz.printers.find("BillPrinter");
}).then(function(printer) {
var config = qz.configs.create(printer);
var data = [
`${state.restaurant_name}` + '\x0A',
`${state.restaurant_address}`
]
return qz.print(config, data);
});
}
You have some unnecessary destructuring that is causing your error - this.state.state doesn't exist, yet this line:
let { state } = this.state;
Is equivalent to:
let state = this.state.state;
Remove the curly braces and it'll work fine.
let state = this.state;
Also note that state will be a reference to this.state rather than being another object.
Use arrow function to keep the function in the upper scope as #Ali Torki suggested:
.then(printer => {....})

Is is possible to include a source file in nodejs+puppeteer to add functions?

I know
await page.evaluateOnNewDocument(fs.readFileSync('./helperFunctions.js', 'utf8'));
to add functions to evaluate() context, that is very handy.
But is anyone can provide any example to have the same on the main context ? By example, said I want to add a
page.existsText()
or
existsText()
function with this code from a file to be included/sourced :
existsText = (string) => {
// code goes here
}
What is the way to go ?
If I understand your intention correctly, you would like to import functions from a file into global namespace, without having to assign them to an intermediary variable. Here's a simple way to do this in node.
helperFunctions.js
(function(){
// Assign the function to the scope from where it's called
this.existsText = (string) => {
console.log("Do stuff with " + string);
}
})()
Then when your require it in node.js/puppeteer script it executes at once assigning functions from it to global scope:
require("./helperFunctions");
existsText("global scope");
Result:
Do stuff with global scope
Bonus: using the same functions in page.evaluate
If needed the same helper file can then be used in browser scope:
await page.evaluateOnNewDocument(fs.readFileSync('./helperFunctions.js', 'utf8'));
await page.evaluate(() => {
existsText("browser scope");
});
Do stuff with browser scope
You can add some methods of the Page class from the page object for quick hacking.
const puppeteer = require("puppeteer");
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
// page constructor is Page,
// and we can add some other methods to it's prototype
page.constructor.prototype.myCustomMethod = function() {
return this._frameManager.mainFrame().url();
};
await page.goto("https://example.com");
const customUrl = await page.myCustomMethod();
console.log({ customUrl }); // Returns { customUrl: 'https://example.com/' }
await browser.close();
});
It's as simple as that for some quick hacks. So, let's add some exists method to that.
// get all arguments
page.constructor.prototype.existsText = function(...args) {
// let's assume the argument as a variable called string
return this._frameManager.mainFrame().evaluate(string => {
// create a new regex to find global multiline insensitive results
const searchRegex = new RegExp(string, "gmi");
// find all matchs
return document.querySelector("body").outerHTML.match(searchRegex);
}, args); // pass all arguments
};
const foundText = await page.existsText("more");
console.log({ foundText });
// Result: { foundText: [ 'More' ] }
Again, these are all quick hacks and have their own limitation. Feel free to explore.

How to access an object created within a function from another function

I'm new to JavaScript and NodeJS, and I need to solve this issue quickly.
connection(getSQL2)
.then((table)=> {
table.forEach(row=> {
let obj = {
countryid: row.IdPais,
country: row.NombrePais
};
data.push(obj);
});
});
console.log(obj);
When I try to display the object using console.log, I get undefined, which seems pretty obvious. But what would be an easy way to get it to display the Object 'obj' that was created above?
UPDATE: Just to clarify, console.log is used here only as an example. I need to access the object from outside that function however I can.
Thanks in advance!
Two things going on here.
1) You're using a promise and promises asynchronously resolve. Good rule of thumb is any code that ends with .then(...) is going to be a promise. What that means is that code underneath it can execute before the promise is finished and if it reads those values before the promise has finished resolving they will be read as undefined.
2) You use the let keyword to define your variable which means it will only be defined in the scope:
row => {
let obj = {
countryid: row.IdPais,
country: row.NombrePais
};
data.push(obj);
// Show the object where it is defined
console.log(obj);
}
you can create a global variable, and assign the value to that variable inside the that function.
Then, you will be able to access the variable obj outside the function also.
var temp;//declare a global variable here.
connection(getSQL2)
.then((table)=> {
table.forEach(row=> {
let obj = {
countryid: row.IdPais,
country: row.NombrePais
};
data.push(obj);
temp = obj;//assign value to global variable here
});
});
console.log(temp);//you can access the 'obj' using temp
Hope this helps you.
You need to do this:-
async database()
{
try {
const table= await connection(getSQL2);
if (table!== null)
{
table.forEach(row=> {
let obj = {
countryid: row.IdPais,
country: row.NombrePais
};
console.log('This will resolve the promise',obj);
}
else
{
//anything needed
}
}
catch (error)
{
// Error retrieving data
}
}
async and await are the keywords used in parallel. await keyword will not allow the control to go down until data is fetched.

Categories