how to restrict from opening multiple alert back to back? - javascript

I have written a angular error Interceptor where i am checking for 401 unauthorized or session expired. it works perfect but the problem is i have used multiple GET apis which on session expire throwing multiple 401. i am displaying js alert and re-directing to login page. as i am getting multiple 401 ,the alert box also is showing multiple times.
ex: if i got 3 times 401. the alert box is showing 3 times back to each.
i used flag to check if one alert box is open make it true and the make the rest false.. but it is not working.
intercept(req: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
if (req.url.indexOf('/reset_password') > 1 ||
req.url.indexOf('/login') > 1) {
return next.handle(req);
}
return next.handle(req).pipe(catchError(err => {
if (err.status === 401) {
alert("Sesson expired, Please Login again!");
$('.modal').modal('hide')
this.AuthService.logout()
}
const error = err.error.message || err.statusText;
return throwError(error);
}))
}
i want to display only one alert box not multiple. on click of OK i want to close it.

You can use either debounce or throttle based on the requirements, here is an example implementation for debounce.
As you can see it only triggers once, and only after provided time in miliseconds since last call of the function.
function debounce(func, wait) {
var timeout;
return function () {
var context = this, args = arguments;
var later = function () {
timeout = null;
func.apply(context, args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
const myAlert = debounce((msg) => alert(msg), 1000)
myAlert("alert1");
myAlert("alert2");
You could perhaps change it a little if you want to keep all the messages instead of just the last one. But take into account that i changed implementation of debounce so it isn't exactly a debounce anymore.
var messages = "";
function debounce(func, wait) {
var timeout;
return function () {
var context = this;
messages += arguments[0];
var later = function () {
timeout = null;
func.apply(context);
messages = "";
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
const myAlert = debounce(() => alert(messages), 1000)
myAlert("alert1");
myAlert("alert2");
setTimeout(() => {
// here i wait for another 2000 miliseconds so the function isnt called back to back
myAlert("alert3");
myAlert("alert4");
}, 2000);

Related

Running a debounced function after user has navigated away from page

I have a debounced function of 3 seconds that I send off to an API service for tracking events.
// api.js
import { debounce } from 'lodash'
const submitRecords = debounce(async () => {
await API.submit({ ...data })
// do other stuff here
}, 3000)
Every time there's a user interaction, my application calls submitRecords, waits 3 seconds, and then makes a request to the API service. The problem here is that if the user navigates away before 3 seconds, the call never gets made.
Is there a way to still send the debounced request even when the user has navigated away from the current URL? I read up on window.onbeforeunload but I'm not sure if it's suitable for my use case.
Yes, you can use window.onbeforeunload.
But instead of async/await may be you need some another debounce implementation, or to do it by yourself.
It can be done with debounce implemented by usage setTimeout and storing timer somewhere globally.
In window.onbeforeunload check timer and if present - execute required logic.
Or you can try to use flag that indicates function in debouncing. Like:
const isDebouncing = false;
const submitRecords = () => {
isDebouncing = true;
debounce(async () => {
isDebouncing = false;
await API.submit({ ...data })
// do other stuff here
}, 3000)();
}
window.onbeforeunload = () => {
if (isDebouncing) {
// do request
}
}
Note: Besides just one flag you can store another data related to await API.submit({ ...data }).
Note: in some cases window.onbeforeunload requires preventing event and return value, like:
window.addEventListener('beforeunload', function (e) {
// Cancel the event
e.preventDefault();
// Chrome requires returnValue to be set
e.returnValue = '';
});
Described her: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload

How to call API every 2 seconds until desired result or timeout in async function

I need to call an api to get a status every 2 seconds if the response is running and first return when response is either complete or failed, or until 30 seconds have passed and the function times out.
This is what I have now which works, but I am sure it can be done much more efficient, but I simply can't figure it out at this point:
const getStatus = async (processId) => {
try {
const response = await fetch(`example.com/api/getStatus/${processId}`);
const status = await response.json();
return await status;
} catch(err) {
// handle error
}
}
Inside another async function using getStatus():
randomFunction = async () => {
let status = null;
let tries = 0;
let stop = false;
while (tries <= 15 && !stop) {
try {
status = await getStatus('some-process-id');
if (status === 'complete') {
stop = true;
// do something outside of loop
}
if (status === 'failed') {
stop = true;
throw Error(status);
}
if (tries === 15) {
stop = true;
throw Error('Request timed out');
}
} catch (err) {
// handle error
}
const delay = time => new Promise(resolve => setTimeout(() => resolve(), time));
if (tries < 15) {
await delay(2000);
}
tries++;
}
}
I would prefer to handle the looping inside getStatus() and in a more readable format, but is it possible?
EDIT:
I tried a solution that looks better and seems to work as I expect, see it here:
https://gist.github.com/AntonBramsen/6cec0faade032dfa3c175b7d291e07bd
Let me know if parts of the solution contains any solutions that are bad practice.
Your question is for javascript. Unfortunately I don't drink coffee, I can only give you the code in C#. But I guess you get the gist and can figure out how to translate this into java
Let's do this as a generic function:
You have a function that is called every TimeSpan, and you want to stop calling this function whenever the function returns true, you want to cancel, whenever some maximum time has passed.
For this maximum time I use a CancellationToken, this allows you to cancel processing for more reasons than timeout. For instance, because the operator wants to close the program.
TapiResult CallApi<TapiResult> <Func<TapiResult> apiCall,
Func<TapiResult, bool> stopCriterion,
CancellationToken cancellationToken)
{
TapiResult apiResult = apiCall;
while (!stopCriterion(apiResult))
{
cancellationToken.ThrowIfCancellationRequested();
Task.Delay(delayTime, cancellationToken).Wait;
apiResult = apiCall;
}
return apiResult;
}
ApiCall is the Api function to call. The return value is a TApiResult. In your case the status is your TApiResult
StopCriterion is a function with input ApiResult and output a boolean that is true when the function must stop. In your case this is when status equals complete or failed
CancellationToken is the Token you can get from a CancellationTokenSource. Whenever you want the procedure to stop processing, just tell the CancellationTokenSource, and the function will stop with a CancellationException
Suppose this is your Api:
Status MyApiCall(int x, string y) {...}
Then the usage is:
Timespan maxProcessTime = TimeSpan.FromSeconds(45);
var cancellationTokenSource = new CancellationTokenSource();
// tell the cancellationTokenSource to stop processing afer maxProcessTime:
cancellationTokenSource.CancelAfter(maxProcessTime);
// Start processing
Status resultAfterProcessing = CallApi<Status>(
() => MyApiCall (3, "Hello World!"), // The Api function to call repeatedly
// it returns a Status
(status) => status == complete // stop criterion: becomes true
|| status == failed, // when status complete or failed
cancellationTokenSource.Token); // get a token from the token source
TODO: add try / catch for CancellationException, and process what should be done if the task cancels
The function will stop as soon as the stopCriterion becomes true, or when the CancellationTokenSource cancels. This will automatically be done after maxTimeOut. However, if you want to stop earlier, for instance because you want to stop the program:
cancellationTokenSource.Cancel();

Wait 3 seconds to see if a variable is changed then fire something

Here is a piece of JavaScript Code to do Speech Recognition using Web Speech API. This piece of code is responsible for restarting Speech Recognition after user finished speaking. Now I want to modify this code to give users 3-second chances to speak a different sentence when they saw speechResult variable on their screen.
Here is the scenario:
1) User speaks, Then Voice Recognition puts their speech as text in "speechResult" variable and displays it on their screens.
2) We wait 3 seconds to give the user another chance if he/she wants to speak a different sentence.
3) After 3 seconds without any change in "speechResult", we fire some if statements to assign "isCorrect" variable with true or false values...
recognition.onend = function(event) {
//Fired when the speech recognition service has disconnected.
recognition.start();
// Some code to do: If "speechResult" variable changes, wait for 3
seconds then fire if statement below.//
const debounce = (func, delay) => {
let debounceTimer
return function() {
const context = this
const args = arguments
clearTimeout(debounceTimer)
debounceTimer
= setTimeout(() => func.apply(context, args), delay)
}
}
debounce function() {
if (speechResult == "who are you") {
isCorrect= true;
} else {
isCorrect= false;
}
} }, 3000);
You can use setTimeout like this:
recognition.onend = function(event) {
//Fired when the speech recognition service has disconnected.
recognition.start();
setTimeout(processResult, 3000);
}
function processResult(speechResult) {
if (speechResult == "who are you") {
isCorrect= true;
} else {
isCorrect= false;
}
}
setTimeout returns a number you can use with clearTimeout if you receive a condition that should cancel it. Or you could use a debounce function.

Intercept fetch() request, put it on-hold and resume when certain criteria is met

The following code fires an alert when it detects fetch() request to a certain endpoint. Doing so makes the request stops from proceeding, waits for the user to close the alert and then lets the request flow to the endpoint.
My question is how to achieve the same interruption, but instead of waiting for the alert to be closed, I'd need the request to wait for the appearance of a cookie. I have a feeling it needs to be done with Promises :)
const x = window.fetch;
window.fetch = function() {
if (arguments[0] == '/certain_endpoint') { alert('stopping for a while'); }
return x.apply(this, arguments)
}
You can use setInterval with promises to periodically poll for a certain condition and resolve when it is met.
const x = window.fetch;
window.fetch = function() {
if (arguments[0] == '/needs_cookie') {
return waitForCookie().then(cookie => {
return x.apply(this, arguments);
});
} else {
return x.apply(this, arguments);
}
}
// Returns a promise that resolves to a cookie when it is set.
function waitForCookie() {
return new Promise(function (resolve, reject) {
var intervalID = setInterval(checkForCookie, 100);
function checkForCookie() {
var cookie = getCookie();
if (cookie) {
clearInterval(intervalID);
resolve(cookie);
}
}
});
}
// Here, getCookie() returns undefined the first two times it's called.
// In reality, it should just parse document.cookie however you normally do.
var attempts = 0;
function getCookie() {
if (attempts < 2) {
attempts++;
console.log('Attempts: ', attempts);
return undefined;
} else {
return 'cookie!';
}
}
If you're trying to do more complicated asynchronous stuff, including polling, you may want to check out RxJS.
{
const original = window.fetch
window.fetch = function(...args) {
if (args[0] == '/certain_endpoint') {
return new Promise(res => {
setTimeout(() => res(original(...args)), 1000);
});
}
return original(...args);
};
}
You may return a promise instead that resolves after some time

JS Promise waitFor refresh Token

The situation is simple :
I have a nodejs server (called it API-A) that use Bluebird as a Promise handler.
I have a client(browser) that ask data through the API-A which get the data from another API (API-B). API-B could be a Weather service from example and then API-A aggregate the data with other data and send it back to client.
The situation is the next: API-B need a token with a TTL of 1800 second.
So for each request done by the client, I check if my token is expired or not.
I have this kind of code :
function getActivities()
{
return this.requestAuthorisation()
.then(()=>{
// some other code that is not interesting
})
}
Everything works fine with the glory of promise.
requestAuthorisation() check if the token is valid (next!!!) and if not (I do a request the API-B to refresh the token)
The problem is here:
between the time, the token is expired and the time to obtain a fresh one, some times happen. if 1000 clients ask at the same time these, I will have 1000 request of token to API-B, that is not cool.
How can I avoid that ? I try to avoid a cron-way to do it, to avoid unnecessary call and the problem is the same.
I try to create a sort of global variable (boolean) that track the refreshing status of the token but impossible to find a sort of Promise.WaitFor (variable change)
the Promise.all can not be use because I am in different scope of event.
Is there a way to queue until the token is refresh ?
Please help !
If I understand this write, we need to do two things:
Do not call our refreshToken several times when one is in progress
Once completed, let all the waiting request know that request for the token in completed so that they can continue their work.
If you combine Observable pattern and a state to maintain the in-progress state, this can be done like below
// MyObservable.js:
var util = require('util');
var EventEmitter = require('events').EventEmitter;
let inProgress = false;
function MyObservable() {
EventEmitter.call(this);
}
// This is the function responsible for getting a refresh token
MyObservable.prototype.getToken = function(token) {
console.log('Inside getToken');
if (!inProgress) {
console.log('calling fetchToken');
resultPromise = this.fetchToken();
inProgress = true;
resultPromise.then((result) => {
console.log('Resolved fetch token');
inProgress = false;
this.emit('done', 'token refreshed');
});
}
}
// This is a mock function to simulate the promise based API.
MyObservable.prototype.fetchToken = function(token) {
console.log('Inside fetchToken');
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('resolving');
resolve("Completed");
}, 2000);
});
}
util.inherits(MyObservable, EventEmitter);
module.exports = MyObservable;
Now we can implement this and observe for the call to complete
const MyObservable = require('./MyObservable');
const observable = new MyObservable();
const A = () => {
console.log('Inside A');
observable.on('done', (message) => {
console.log('Completed A');
});
observable.getToken('test');
}
for (let i = 0; i < 5; i++) {
setTimeout(A, 1000);
}
If we run this code, you will get an output where fetchToeken is called only once even though our method A is called 5 times during the same duration.
Hope this helps!

Categories