Is there better approach for auto background saving in web? - javascript

I have this code and having a hard time figuring out what to do, wherein the UI there is a save button and an interval saving. if the interval saving is in progress then the user hits the save button, the same request on the button should deny this request. for now, in my code, I subscribe on this BehaviourSubject variable to see it there in progress then execute request if false.
is there any mechanism or another best approach for this rather than flagging? because I face an issue, what if the interval saving and saving button is triggered and same second/moment/time?
Observable.interval(180000).subscribe((data) => {
if (!this.saveService.getSavingProgress()) {
this.saveService.autoSave().subscribe((status) => {
}
}

Use the throttle operator provided by RxJS https://rxjs-dev.firebaseapp.com/api/operators/throttle

Related

ClearInterval js stop current execution

I have a Vue 2.0 app in which I use this line in order to call this.refreshState() every min.
this.scheduler = setInterval(() => this.refreshState(), 60 * 1000)
Later in the code I need to make sure that the execution loop is stopped and also that if there's an instance of this.refreshState() currently running (from the setInterval scheduler) it's stopped as well (even if it's in the middle of doing stuff).
So far I'm using :
clearInterval(this.scheduler)
as per (https://developer.mozilla.org/en-US/docs/Web/API/clearInterval)
The question I'm having is does clearInterval blocks the current execution if any? I can't find the answer in the doc unfortunately.
FYI the code of refreshState:
refreshState: function () {
// API call to backend
axios.get("/api/refreshState")
.then(response => {
this.states = response.data.states
})
.catch((err) => console.log(err)
}
Here's my use case :
alterState: function (incremental_state) {
clearInterval(this.scheduler) // ???
axios.post("/api/alterState", incremental_state)
.then(() => {
this.refreshState()
this.scheduler = setInterval(() => this.refreshState(), 60 * 1000)
})
.catch((err) => { console.log(error) })
}
I want to make sure that when i exit alterState , the variable this.states takes into account the addition of incremental state.
From...
I want to make sure that when i exit alterState, the variable this.states takes into account the addition of incremental state.
...I understand you're performing a change on backend and you want it reflected on frontend. And that currently that doesn't happen, although you're calling this.refreshState() right after getting a successful response from /api/alterState. 1
To achieve this functionality, it's not enough to call this.refreshState(), because your browser, by default, caches the result (it remembers the recent calls and their results, so it serves the previous result from cache, instead of calling the server again), unless the endpoint is specifically configured to disable caching.
To disable caching for a particular endpoint, you could either
configure the endpoint (server side) to tell browsers: "Hey, my stuff is time sensitive, don't cache it!" (won't go into how, as I have no idea what technology you're using on backend and it varies). Roughly it means setting appropriate response headers.
or call the endpoint with a unique param, each time. This makes the endpoint "change" from browser's POV, so it's always going to request from server:
axios
.get(`/api/refreshState?v=${Date.now()}`)
.then...
I recommend the second option, it's reliable, predictable and does not depend on server configuration.
And, unless something else, other than the current app instance (some other user, or other server scripts, etc...) make changes to the data, you don't actually need a setInterval. I suggest removing it.
But If you do have other sources changing server-side data, (and you do want to refresh it regardless of user interactions with the app), what you have works perfectly fine, there's no need to even cancel the existing interval when you make a change + refreshState()). 2
1 - if I misunderstood your question and that is not your problem, please clarify your question, right now it's a bit unclear
2 - as side-note and personal preference, I suggest renaming refreshState() to getState()

Angular, to many API calls on input 'on-change'

I am using angular 8.
There is one auto-complete input and if it's value changes I have to make API call and load new suggestions for this input.
//In Template
<autocomplate [suggestions]="suggestions" (filterChange)="filterChange($event)"></autocomplate>
//In Component
filterChange(e) {
console.log(e)
this.loadSubscriptions(e ? { 'filterItem.name': e } : {})
}
loadSubscriptions(params) {
if (this.suggestionsSubscriber) this.suggestionsSubscriber.unsubscribe()
this.suggestionsSubscriber = this.suggestionsService.loadData(params).subscribe(
data => this.suggestions = data
})
}
Everything works fine, but the problem is when user types fast application makes to many requests.
Can I somehow delay requests if user types fast? for example, while the user is typing don't make API calls on every change, and if the user stops typing then make API call.
Or if you have a better way to solve this problem, please share.
Use RXJS denounceTime operator. Simply chain it to your Observable.
Whenever debounceTime receives an event, it waits a designated amount of time to see if another event comes down the pipe. If it does, it restarts its timer. When enough time has passed without another event streaming in, it emits the latest event.
I would suggest you to use throttle or debounce. You can write your own implementation for those or use library such as lodash.
Debounce using latest Rxjs can be a work around. Please see below for implementation.
Angular and debounce
I also had a same problem, so i put my code inside setTimeout as below
filterChange(e) {
console.log(e)
setTimeout(()=>{
this.loadSubscriptions(e ? { 'filterItem.name': e } : {})
},2000);
}
Now if you type very fast then it will not call the loadSubscriptions at that time. it will call after 2 sec.
You can configure the time according to your choice.
I hope This will helps you.

Heartbeat method in Meteor

I have a Meteor application that, for every second while the user is holding a button, decrements a value on a post by 1. There are many many buttons, and each should only affect itself.
If one person is holding the button, it will go down by a rate of one per second. If two people (on different clients) then by two per second.
The exact moment at which it is updated in the database is unnecessary, only that the client should see the counter decrement by a variable amount each second.
So to trigger the method I used the following
Template.button.onRendered(function() {
var data = this.data;
Meteor.setInterval(function() {
if(isClicked) {
Meteor.call('heartbeat', data);
}
}, 1000);
});
which calls a client/server method
'heartbeat': function(button) {
Buttons.update({_id: button._id}, {$inc: {life: -1}});
if(button.life <= 1) {
console.log('REMOVE DEAD BUTTONS');
Buttons.remove({life: {$lte: 0}});
}
}
And causes weird activity when latency comes into play. When I click on a button, its life goes down predictably at 1hz on my client. On a different client, its life might stand still for several seconds, and then decrement in chunks of 2 to 4 until it catches up. It is supposed to just jump to the new value as soon as it hears from the server that it's been updated, rather than ramping down.
But since there is no code to make it ramp, I am led to believe that there is something more fundamentally wrong in play. There are three states a button goes through:
Client A decrements value -> Server decrements value -> Client B reads value
The problem seems to between Client A and the server, so perhaps setting an interval to call a method every second is the bottleneck here that I need to fix, but I'm not sure of any elegant solutions. If instead of sending each update, I adopted a dead reckoning approach and send the start and ends and had the server interpolate on each second in between, that might alleviate some issues, but I don't know if I'm going to run into more unexpected issues along that line.
Is there a significantly better way of decrementing a counter on the second every second for every client reactively?
An alternate approach:
When the user presses the button (catch this in a template event handler), make a Meteor.call() to the server and have the server decrement every second.
When the user releases the button, make another Meteor.call() to cancel the decrementing. You'll need to keep a handle to the setInterval so you can cancel it.
This way you'll remove the client->server lag for doing the updates.

Prevent JavaScript Timer Re-entry

My ASP.NET MVC page uses JavaScript/jQuery to poll my database every second.
This is working but I want to make sure that, if there is a delay, my timer handler won't get called again before it has returned.
In there any trick to this other than storing the timer ID in a global variable, clearing the timer in my handler, and restarting it when my handler is done.
NOTE: I realize every second seems frequent but this code is polling my server after submitting a credit card payment. Normally, it will only run for a second or so, and I don't want the user to wait any longer than necessary.
Polling every second? That's quite heavy!
That aside, you won't have this issue when setTimeout is used instead of setInterval. The latter ensures that a piece of code is run x times given a interval, while the former ensures that there's a delay of at least x milliseconds.
function some_poller() {
$.ajax({
url: '/some_page',
success: function() {
setTimeout(some_poller, 1000);
},
error: function() { // Also retry when the request fails
setTimeout(some_poller, 1000);
}
});
}
// Init somewhere
some_poller();
Not really, although I wouldn't recommend using a global variable. Stick it inside some function.
But are you really sure you need to poll every second? That's an extremely chatty interface.
In my personal experience a "global", (inside of the root function), variable works very well in this instance so that you can control when to clear and restart. If the response is really as quick as you say, this shouldn't cause too much overhead, (clearing/resetting), and will allow to account for these type of situations.

Clear Form Fields on Inactivity

I'm currently working on a simple form that stores users inputted information to a database.
The form will be displayed on iPads at a Kiosk.
If a user walks up to the form and starts to fill in the fields, but doesn't finish and walks away, I want the form fields to clear for the next person.
This is being done to prevent someone from walking up to an iPad with half of the previous users information that was never submitted.
I know I'll have to use Javascript, but I have no clue where to start.
I would say handle the keydown event of the window object and save the current time. Something like this:
var timerID = null;
var timeoutDuration = 60000; // Put the timeout duration here
window.addEventListener('keydown', function(e) {
if(timerID !== null) {
clearTimeout(timerID);
timerID = null;
}
timerID = setTimeout(function() {
// Clear all the fields here
}, timeoutDuration);
}, false);
Here's a demo.
Why not just reload the page after a period of inactivity? Safer bet. Just use setTimeout and clearTimeout JavaScript functions to achieve this when the fields get updated to reset the timers. Use setTimeout to reload the page. This will ensure that the page is reset.
See Reload and JavaScript timing.
In my opinion, the best thing to use it the javaScript timing event.
This can be done by setTimeout() and clearTimeout() functions. Then in those functions you can address the input boxes document.getElementById("nameofElement") and then clear them.
Good example that is easy to follow see :
JavaScript Timing Events
Hope this helps.

Categories