acync await react/redux js async events - javascript

https://ibb.co/dsNrnPQ -- screenshot of error
I get a problem with an async event.
When logging into the site, when locale-storage is not ready yet. I can't get it async.
After refreshing the page, the problem goes away.
Unhandled Rejection (SyntaxError): Unexpected token u in JSON at position 0
Problem in string
const userData = await userDataGetter();
export function setBalanseFetch(){
return async dispatch => {
const userData = await userDataGetter();
const userID = await userData.userId;
try{
const respone = await axios.post('/api/profile', {userID})
const json = await respone["data"];
const FetchBalanse = json.items[0].balanse;
dispatch( {type: FETCH_BALANSE, payload: Number(FetchBalanse)})
}catch(e){
console.log(`Axios spend balanse request failed: ${e}`);
}
}
}
code function userDataGetter
async function userDataGetter(){
const userData = await JSON.parse(localStorage.userData);
return userData;
}
export default userDataGetter

You have:
const userData = await JSON.parse(localStorage.userData);
However, JSON.parse is not an asynchronous function. It does not wait for a localStorage key to be present and ready, which is what your code seems to want it to do. (Also, as a comment pointed out, you want localStorage.get('userData')). Nor are you checking that it is present at all.
You also don't show where the localStorage is getting set. But likely your solution will be to then trigger the code that depends on it after you know its been set from the same place that's setting it, and when you need to access it any other time, check for its presence first.

Related

API Call only works on homepage but not subpage?

I'm relatively new working with promises in JS. I got the API call to work on the initial homepage, but I'm having issues when I go to another page that is using the same API call.
In my api.js file I have the following:
const key = apiKey;
const commentsUrl = axios.get(`https://project-1-api.herokuapp.com/comments/?api_key=${key}`);
const showsUrl = axios.get(`https://project-1-api.herokuapp.com/showdates?api_key=${key}`);
async function getData() {
const allApis = [commentsUrl, showsUrl];
try {
const allData = await Promise.allSettled(allApis);
return allData;
} catch (error) {
console.error(error);
}
}
In my index.html
import { getData } from "./api.js";
let data = await getData(); //This works and gathers the data from the API.
In my shows.html
import { getData } from "./api.js";
let showsData = await getData(); //This does not and says that cannot access commentsUrl (api.js) before it is initialized. But it is?
If I comment out the code from "show", the API GET request works fine and the index page loads the API data correctly. Can anyone explain to me what's happening and why I would be getting the uninitialized error?
I also should note that if I split the API calls onto two seperate two js files (one for the index, one for the shows), the API calls works and displays the data as it is intended to.
On the homepage, the code is executing the 2 GET requests on page load/initialization of the JS code. When you navigate away from the homepage, presumably with some sort of client-side routing, the 2 GET requests no longer reference 2 Promises as they have already been executed.
You could instead move the GET requests into your function like:
const key = apiKey;
async function getData() {
try {
const commentsUrl = axios.get(`https://project-1- api.herokuapp.com/comments/?api_key=${key}`);
const showsUrl = axios.get(`https://project-1-api.herokuapp.com/showdates?api_key=${key}`);
const allApis = [commentsUrl, showsUrl];
const allData = await Promise.allSettled(allApis);
return allData;
} catch (error) {
console.error(error);
}
}

Call an async function with javascript

I am trying to call an async function but I am getting an error
getUsersList(db).then is not a function
this is my code
async function getUsersList(db) {
const userCol = collection(db, 'Users');
const userSnapshot = await getDocs(userCol);
const tempUserList = userSnapshot.docs.map(doc => doc.data());
return tempUserList;
}
function App() {
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const auth = getAuth(app);
var currentUser = auth.currentUser;
if(currentUser != null){
getUsersList(db).then((value) => {
console.log(value);
});
I also tried using await getUsersList but got the following error
Unexpected reserved word 'await'
So what I assume you're trying to do here const userSnapshot = await getDocs(userCol); is fetch some data that is then going to be used in your react component to render something (Maybe there's a fetch request in getDocs ?)
There is no return in your react component (but that's not what's causing your issue).
As it is it won't work using await since App() isn't an async function BUT you can't make it an async function since this is a standard react component.
What do you want to happen whilst waiting for the data to be fetched (= whilst your promise is pending) ? If you're happy to display nothing, why not just remove await before getDocs() ?
For more on this topic :
React: async and await not working with fetch
React Hooks: how to wait for the data to be fetched before rendering

Error message : SyntaxError: Unexpected token < in JSON at position 0

i was trying to fetch a data for a project but everytime i'm converting the fetch data to json it returns me
SyntaxError: Unexpected token < in JSON at position 0
i don't understand why it's showing me this
import React,{useContext,useState,useEffect} from 'react'
const url = 'www.thecocktaildb.com/api/json/v1/1/search.php?s='
export default function AppProvider({children}) {
const [loading,setLoading] = useState(true)
const [searchTerm,setSearchTerm] = useState('a')
//set it as 'a' for suggestion at search bar at beginning.
const [cocktails,setCocktails] = useState([])
const fetchUrl = async ()=>{
setLoading(true)
try {
const response = await fetch(`${url}${searchTerm}`)
//(${url}${searchterm} helps me to fetch data at first with names that starts with 'a' for suggestion///
const data = await response.json()
setLoading(false)
} catch (error) {
console.log(error)
}
}
useEffect(()=>{
fetchUrl()
},[searchTerm])
please visit the API page from the URL & see if there's an issue with the data. the data is not fetching. what's the issue?
Link
Doing
fetch('www.thecocktaildb.com/')
will fetch not that website, but that path relative to the current path. For example, doing so here on Stack Overflow results in the URL being fetched being
https://stackoverflow.com/questions/72914244/www.thecocktaildb.com/
which, of course, doesn't exist - and presumably that URL doesn't exist on your site either.
Use the full path.
const url = 'https://www.thecocktaildb.com/api/json/v1/1/search.php?s='
I'd also recommend only calling the API when searchTerm isn't empty, and perhaps add a debounce of a few hundred milliseconds so as not to call it too often and to keep the client from being blocked.

Node.js: share connection object throughout the application

I am a having issues with implementing generic-pool using puppeteer. Below is my relevant part of the code.
UPDATE
Thanks #Jacob for the help and i am more clear about the concept and how it works and the code is also more readable and clear. I am still having issues where a generic pool is getting created on every request. How do i ensure that the same generic pool is used every time instead of creating new one
browser-pool.js
const genericPool = require('generic-pool');
const puppeteer = require('puppeteer');
class BrowserPool {
static async getPool() {
const browserParams = process.env.NODE_ENV == 'development' ? {
headless: false,
devtools: false,
executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
}
:
{
headless: true,
devtools: false,
executablePath: 'google-chrome-unstable',
args: ['--no-sandbox', '--disable-dev-shm-usage']
};
const factory = {
create: function() {
return puppeteer.launch(browserParams);
},
destroy: function(instance) {
console.log('closing browser in hrere.....');
instance.close();
}
};
const opts = {
max: 5
};
this.myBrowserPool = genericPool.createPool(factory, opts);
}
static async returnPool() {
if (this.myBrowserPool == "") {
getPool();
}
return this.myBrowserPool.acquire();
}
}
BrowserPool.myBrowserPool = null;
module.exports = BrowserPool;
process-export.js
const BrowserPool = require('./browser-pool');
async function performExport(params){
const myPool = BrowserPool.getPool();
const resp = BrowserPool.myBrowserPool.acquire().then(async function(client){
try {
const url = config.get('url');
const page = await client.newPage();
await page.goto(url, {waitUntil: ['networkidle2', 'domcontentloaded']});
let gotoUrl = `${url}/dashboards/${exportParams.dashboardId}?csv_export_id=${exportParams.csvExportId}`;
//more processing
await page.goto(gotoUrl, {waitUntil: 'networkidle2' })
await myPool().myBrowserPool.release(client);
return Data;
} catch(err) {
try {
const l = await BrowserPool.myBrowserPool.destroy(client);
} catch(e) {
}
return err;
}
}).catch(function(err) {
return err;
});
return resp;
}
module.exports.performExport = performExport;
My understanding is that
1) When the application starts I can spin up for example 2 chromium instances and then when ever i want to visit a page i can use either of the two connections, so the browsers are essentially open and we improve the performance since the browser start can take time. is this correct?
2) Where do I place the acquire() code, I understand this should be in the app.js, so we acquire the instances rite when the app boots, but my pupeteer code is in a different file, how do i pass the browser reference in the file which has my pupeteer code.
When I use the above the code, a new browser instances spins up every time and the max property is not considered and it opens up as many instances are requested.
My apologies if its something very trial and i might have not understood the concept fully. Any help in clarifying this would be really helpful.
When using a pool, you'll need to use .acquire() to obtain an object, and then .release() when you're done so the object is returned to the pool and made available to something else. Without using .release(), you'd might as well have no pool at all. I like to use this helper pattern with pools:
class BrowserPool {
// ...
static async withBrowser(fn) {
const pool = BrowserPool.myBrowserPool;
const browser = await pool.acquire();
try {
await fn(browser);
} finally {
pool.release(browser);
}
}
}
This can be used like this anywhere in your code:
await BrowserPool.withBrowser(async browser => {
await browser.doSomeThing();
await browser.doSomeThingElse();
});
The key is the finally clause makes sure that whether your tasks complete or throw an error, you'll cleanly release the browser back to the pool every time.
It sounds like you might have the concept of the max option backwards as well and are expecting the browser instances to be spawned up to max. Rather, max means "only create up to max number of resources." If you try to acquire a sixth resource without anything having been released, for example, the acquire(...) call will block until one item is returned to the pool.
The min option, on the other hand, means "keep at least this many items on hand at all times", which you can use to pre-allocate resources. If you want 5 items to be created in advance, set min to 5. If you want 5 items and only five items to be created, set both min and max to 5.
Update:
I notice in your original code that you destroy in case of error and release when there isn't an error. Still would prefer the benefit of a wrapper function like mine to centralize all resource acquiring/releasing logic (the SRP approach). Here's how it could be updated to automatically destroy on errors instead:
class BrowserPool {
// ...
static async withBrowser(fn) {
const pool = BrowserPool.myBrowserPool;
const browser = await pool.acquire();
try {
await fn(browser);
pool.release(browser);
} catch (err) {
await pool.destroy(browser);
throw err;
}
}
}
Addendum
Figuring out what's going on in your code will be easier if you embrace the async function instead of mixing async function stuff and Promise callback stuff. Here's how it can be rewritten:
async function performExport(params){
const myPool = BrowserPool.myBrowserPool;
const client = await myPool.acquire();
try {
const url = config.get('url');
const page = await client.newPage();
await page.goto(url, {waitUntil: ['networkidle2', 'domcontentloaded']});
let gotoUrl = `${url}/dashboards/${exportParams.dashboardId}?csv_export_id=${exportParams.csvExportId}`;
//more processing
await page.goto(gotoUrl, {waitUntil: 'networkidle2' })
await myPool.release(client);
return Data;
} catch(err) {
try {
const l = await myPool.destroy(client);
} catch(e) {
}
return err; // Are you sure you want to do this? Would suggest throw err.
}
}

Flow Type with Async Await error checking Javascript

I can't figure out why this code isn't passing the flow checker. I simply send an object to the updatePopper function and inside it I make an api call to update the data in the DB, and then I get a response, decode that response, and return that new updated data to the client-side and update the redux-form with the latest data. But flow doesn't like my code. Any ideas would be awesome!
This is the error popping up:
// Code in my react submit function
const newPopper: {data: Popper} = await this.props.updatePopper(data)
// Code in my redux action
export const updatePopper = (data: Popper) => async (dispatch: DispatchActionDynamic): {data: Popper} => {
// Make API REQUEST
const response = await PopperApi.updatePopper(popperData)
// Decode JSON
const body: PopperResponse = await response.json()
// Check for Valid response and error handling
await statusCheck(response, dispatch)
// update redux with new data
dispatch(updatePopper(body))
// return response
return body
}

Categories

Resources