Fetch is taking longer than usual - javascript

I'm doing a simple fetch as follows
useLayoutEffect(() => {
var v1 = performance.now();
fetch('https://example.com/api/')
.then(result => {
var v2 = performance.now();
console.log("total time taken for fetch = "+(v2-v1)+"milliseconds");
return result.json()
})
.then(data => {
var v3 = performance.now();
console.log("total time taken = "+(v3-v1)+"milliseconds");
console.log(data.data);
})
},[])
In the server side, I included the server execution time which shows 0.00759 seconds to process the entire php script including the php query.
I have access the API directly via browser and it's extremely fast as well, almost instantly.
However when I use react/javascript, there is a huge delay sometimes up to 7-10 seconds.
I wish to know how I can find out where is the bottleneck for the lag/delay.

Related

How to fetch timestamp based on the internet instead using user's device time in Javascript?

I tried to create a get timestamp function like Date.now(). I assume that Date.now() will use the time from the user's computer, so there is no guarantee that the UNIX time is accurate if the user sets the time manually. I would create a function to get a standardized timestamp from the time server API instead, to make sure that the timestamp is the same for all of the users.
function timefromInternet() {
return new Promise((resolve, reject) => {
fetch("http://worldtimeapi.org/api/timezone/Asia/Taipei")
.then(response => response.json())
.then(data => {
resolve(data.unixtime);
}).catch(error => { resolve(Date.now()); });
});
}
but it is too slow, so I could not execute like Date.now() for example like this:
let callInfo = {
timestamp: Date.now(),
status: "PAUSE",
};
this.$store.commit("setCallInfo", callInfo);
this.$store.commit("updateLocalUserByObject", {
status: callInfo.status,
});
I want to replace Date.now() with something like this:
let callInfo = {
timestamp: timefromInternet(),
status: "PAUSE",
};
this.$store.commit("setCallInfo", callInfo);
this.$store.commit("updateLocalUserByObject", {
status: callInfo.status,
});
What is the best solution to modify timefromInternet() so it could be run like Date.now()? Because if I am using promises, I could not call like Date.now() above. Thanks in advance.
You can request the time only once at page load and then make your getTimeStamp() synchronous.
There are a few clock timers available in the browser, some that the users can't easily mess with. For instance performance.now() will be relative to the page load and will use a monotonic clock which should keep ticking, no matter what the user does with its System Settings (contrarily to Date, which in some UAs always request the system date, not only at page load).
One case where this clock may stop ticking is when the computer goes to sleep. One workaround for that is to make a new request when the page gains focus again.
async function fetchExactDateFromServer() {
const resp = await fetch("https://worldtimeapi.org/api/timezone/Europe/Paris");
if (!resp.ok) {
throw new Error("Network Error");
}
return +new Date((await resp.json()).datetime);
}
let offset = 0;
function getTimeStamp() {
return Math.round(performance.now() - offset);
}
function updateTime() {
return fetchExactDateFromServer()
.then((officialTime) => {
offset = performance.now() - officialTime;
})
.catch((err) => {
console.error(err);
return Promise.reject(err);
});
}
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === 'visible') {
updateTime();
}
});
// test by logging the difference between server-side and local (should always be about the same difference)
const btn = document.querySelector("button");
updateTime().then(() => {
btn.onclick = (evt) => console.log(getTimeStamp(), Date.now(), getTimeStamp() - Date.now());
btn.disabled = false;
});
<button disabled>Test</button>
I think that after reading your comments (in regard to protecting against free trial abuses) you're approaching this in logically the wrong way.
Even with a super-efficient way of pulling an accurate timestamp from the Internet in some way, it is actually trivial for anyone to simply replace the function/return locally in their browser, and so defeat your test. They don’t even need to supply a timestamp, they can just replace the function with something that returns TRUE for every test. Why? Because anything you test in the client (browser) is open to modification by a reasonably sophisticated user, which means that all validation must be enforced server-side if it is to avoid being circumvented.
As an alternative, simply store the trial period details at the server end (where you have total control over the validity of the timestamp), and if a request from the user is made after the trial has expired, then reject it.
You should trust the system clock. Virtually all modern OSen are running an NTP daemon of some flavour or other.
There's too much stuff these days, Kerberos off the top of my head, and SSL/TLS, that depends on clock synchronicity for them to do otherwise.
About the only exception might be systems in a hardened, air-gapped, environment. And they've probably got an accurate time source of their own (GPS receiver, atomic clock radio, etc.)

Output execution time for a Playwright step with AJAX payload

I am trying to dump out a few key measurements to console when my test runs, rather than getting them from the reporter output, but I can't see how to grab the time taken for the last step to execute. Here's a simplified version based on the docs for request.timing() but I don't think that what I'm doing is classed as a request:
const { test, expect } = require('#playwright/test');
test('ApplicationLoadTime', async ({ page }) => {
// Wait for applications to load
await page.waitForSelector('img[alt="Application"]');
// Not working! - get time for step execution
const [fir] = await Promise.all([
page.click('text=Further information requested'),
page.waitForSelector('img[alt="Application"]')
]);
console.log(fir.timing());
});
The click on "Further information requested" causes the page to be modified based on an AJAX call in the background and the appearance of the Application img tells me it's finished. Is this possible or do I need to rely on the reports instead?
fir is going to be undefined in your code as page.click() doesn't return anything. You need to wait for the request whose timing you're interested in, use page.waitForEvent('requestfinished') or waitForNavigation:
const { test, expect } = require('#playwright/test');
test('ApplicationLoadTime', async ({ page }) => {
// Wait for applications to load
await page.waitForSelector('img[alt="Application"]');
const [fir] = await Promise.all([
// Wait for the request
page.waitForEvent('requestfinished', r => r.url() == '<url of interest>'),
page.click('text=Further information requested'),
page.waitForSelector('img[alt="Application"]')
]);
console.log(fir.timing());
});

ReactJS : How to detect network idle between XHR requests

I'm fairly new to the JS world and working with React JS. Couldn't find anything for the exact solution.
I want to implement an App level idle timer which would be activated when the user does not make any server request for a specific time period. The function should be triggered after X mins of the last XHR request irrespective of whether the user navigates between components or not.
For example - If user clicks on a button which calls an API and just plays around the screen without making another service call for X mins, the function should be triggered. At this stage, though user is not idle on the website, there's an idleness in the network activity. I want to detect this and perform some actions.
Also, would like to know the performance impact of the solution. Thanks!
Use PerformanceObserver to detect the fetch and then add/update timer using the setTimeout
let timer;
const observer = new PerformanceObserver((items) => {
items
.getEntries()
.filter(({ initiatorType }) => initiatorType === "fetch")
.forEach((entry) => {
console.log("Made fetch request", entry.name);
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => console.log("(idle) After 2 sec"), 2000);
});
});
observer.observe({
entryTypes: ["resource"],
});
fetch("https://swapi.dev/api/planets/1/").then((res) => res.json());
setTimeout(
() => fetch("https://swapi.dev/api/planets/2/").then((res) => res.json()),
1000
);
setTimeout(
() => fetch("https://swapi.dev/api/planets/3/").then((res) => res.json()),
3000
);
The Network Information Api.
I'm not sure but you can try subtract downlink from downlinkMax.
But this Api is not well supported Can i use

NodeJS: How to generate all previous cached requests automatically on expiration

I'm building a Blog API using Nodejs and my data coming from a scraping service that scraped data from multiples news websites live, so there's no database.
The scraping service takes around 30 seconds to return a response for page 1 of all sites I scraping with. ( Imagin with me how pagination will be looks like in my app :( )
If you don't know what scaping is just thinking of it as multiple APIs
and I get data from each one then combine all in one results array.
So because of the long response time, I start using the node-cache package for caching and it saves my request time from 30 seconds to 6 milliseconds ( Wooow right? )
The problem is when my cache gets expired after x time, I need to wait for a random user to hit my endpoint again to regenerate the cache again with the new data and he will wait for the whole 30 seconds until he gets a response.
I need to avoid that as much as I could, so any Ideas? I have searched a lot and not getting any useful results!!, All articles talk about how to cache not techniques.
#Update
I have found kinda a solution the package I'm using for caching provided in their API Documentation an event called cache.on('expired', cb) means I can listen to any cache get expired.
What I have done is kinda an endless loop making the request to my self every time a cache get expired
The code
class MyScraperService {
constructor() {
this.cache = new NodeCache({ stdTTL: 30, checkperiod: 5, useClones: false });
this.cache.on('expired', (key: string, data: Article[]) => {
console.log('key: ', key);
// send a request to get all my articless again and again once the cahce get expires
this.articles( key.charAt( key.length -1 ) ); // page number
});
}
async articles(page: string): Promise<Article[]> {
// nodeCache()
if (this.cache.get(`articles_page_${page}`)) {
let all: Article[] = this.cache.get(`articles_page_${page}`); //.sort(() => Math.random() - 0.5);
return all.sort(() => Math.random() - 0.5);
}
let artilces: any = await Promise.all([
this.xxScraper(page),
this.xxScraper(page),
this.xxScraper(page),
this.xxScraper(page),
this.xxScraper(page),
this.xxScraper(page),
this.xxScraper(page),
this.xxScraper(page),
this.xxScraper(page),
this.xxScraper(page)
]);
let all: Article[] = [];
for (let i = 0; i < artilces.length; i++) {
const article = artilces[i];
all.push(...article);
}
this.cache.set(`articles_page_${page}`, all);
all = all.sort(() => Math.random() - 0.5);
return all;
}
}
You might be able to schedule a cronjob to call your scraper every [cachingTime-scrapExecutionTime](in this case, 30) seconds with cron.
I would also suggest you to increase the caching request to above 1m, which will divide the number of requests to the other websites.

Set Timeout not working in React Native - Debug JS Remotely

I drove myself nuts trying to figure out what the problem is with my code. I am building a React Native application and developing in the IOS Simulator after running run-ios. I enabled Debug JS Remotely so I can verify the condition of my tokens returned from the server.
I am attempting to build a simple service that will refresh my tokens using a setTimeout.
let sessionTimeout = null;
export const session = (response) => {
let tokens = response.tokens;
Store.set(tokens);
setSessionTimeout(tokens.access.expiresIn);
};
const setSessionTimeout = (duration) => {
let time = duration - 5000;
clearTimeout(sessionTimeout);
sessionTimeout = setTimeout(() => {
console.log('settimeout called');
refreshToken();
}, 1000);
};
const refreshToken = () => {
let tokens = Store.get();
refresh(tokens)
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
};
In the above code a began my initial test by hardcoding 1000 and it worked fine. It successfully made the call to my server. I then attempted to implement the proper time duration and found it does not work. Even by replacing the 1000 with 2000 causes it to fail and the call to the backend is never made.
I then tried using the following packages and got the same result:
react-native-timer
react-timer-mixin
After banging my head on the wall for two days and having another attempt on stack shot down because my issue could not be reproduced I disabled the Debug JS Remotely and everything works as expected.
However now I am wondering how I am supposed to debug the frontend portion of my application with out the use of this feature. If anyone has any ideas or advice on issues like this I would appreciate the feedback as this is my first React Native app.

Categories

Resources