I have this situation, i'm building a shopping cart, and i need to make a http request each time a product is added or its quantity is changed.
I have one button to add 1 unit of a product to the cart, it supposed that each unit added should make the http request, but i want to avoid to make to many calls at once... So i wanted to set a timeout for the request, but if within 3 secs the user clicks again, then i should cancel the last request with old data and then set a new timeout fot the request with the new data.
So i came up with this solution
function doRequest(){
clearTimeout(state.request);
state.request = setTimeout(updateCartService, 180);
}
The function is inside another function that retrieves the state object (A collection of variables and data persistent through all the application). The updateCarteService function contains the http request.
However all the requests are still being made, if i click 5 times the button that triggers doRequest, the call i being excecuted 5 times.
Have any idea of what could be wrong or pherhaps a better aproach to achieve my goal?
If it helps i'm bulding the site using vueJs, vuex (flux) and this code is inside an action.
setTimeout takes milliseconds, so you set timout for 180ms, it is too short, try 3000 for example. Here a small jsfiddle example.
https://jsfiddle.net/ShinShil/5fw2c63o/
var timeout;
$('#click').click(function() {
clearTimeout(timeout);
timeout = setTimeout(setText, 3000);
});
function setText() {
$('#text').append('text');
}
Related
I have ASP Web Forms Web application, which is used for searching in my database. I have page which contains gridview and also text input field for filtering results.
Input field has onkeyup event which run postback by JavaScript for refreshing the gridview from codebehind.
And also in codebehind I have method, which does saving state last filter request, and if request do not equal previously filter request, then I run new query to database.
My problem - onkeyup event on text input field may generate multiple postbacks. If it first postback, then server will execute the query to database. But following postbacks do not execute and overlap first results. And therefore my gridview stay old state.
<script type="text/javascript">
function DoUpdateGridView() {
var timeout = null;
clearTimeout(timeout);
timeout = setTimeout(function () {
Sys.WebForms.PageRequestManager.getInstance()._doPostBack('<%=GUIGridUpdatePanel.ClientID%>', '<%=GUIGridUpdatePanel.UniqueID%>');
}, 1000);
};
</script>
How you may see I set delay for execute JavaScript, but this only Delays execution of the code but does not interrupt.
I think i may make cache first results, and return it.
But I need know all solutions for this problem.
Сan there be any way to perform only the latest event from the JavaScript?
But then somebody may send multiple request and my web application may fall (DDOS).
You can't interrup what is already happening on the server, but there is an issue with your "delay" code. You need to persist the timeout variable between calls.
Try:
<script type="text/javascript">
//New Position for timeout variable
var timeout = null;
function DoUpdateGridView() {
//This will now clear the existing timneout function
clearTimeout(timeout);
timeout = setTimeout(function () {
//For debug purposes only
console.log("About to postback");
Sys.WebForms.PageRequestManager.getInstance()._doPostBack('<%=GUIGridUpdatePanel.ClientID%>', '<%=GUIGridUpdatePanel.UniqueID%>');
}, 1000);
};
</script>
When two (or more) postbacks are made from the same client at the same time, they send the same ViewState data to the server as part of each request. Control state is part of ViewState. Assuming Session is being handled in the default manner, these requests are processed by the server serially.
Let's say the server alters controls while handling the first request. Then the second request is processed. But since both postbacks were generated at the same time, the second request has the same ViewState (and thus the same control state) as the first request, so the state of the controls that the server sees is the state before the first request was processed, and not the state after the first request was processed!
The simplest solution is to store the pieces of state you are using to determine whether to change the controls in the Session, which by default is stored in memory on the server, thus making the two requests distinguishable.
I have a form which contains one drop down, check box and four buttons. When any of the action is performed (check/uncheck or drop down selection or button click), it has to trigger a service call and the below section should be updated. There may be a chance that the multiple actions can be performed one after other immediately. If this is the case, http call should be triggered only after last activity.
Would be nice if there is any workable idea for this. I feel the timeout can helpful to wait for user to complete all activities (waiting for certain time after each activity) and call http service.
I guess thats what you need:
var timeoutPromise;
var delayInMs = 2000;
$scope.$watch("your_form_scope", function(newValue, oldValue) {
$timeout.cancel(timeoutPromise); //does nothing, if timeout alrdy done
timeoutPromise = $timeout(function(){ //Set timeout
//your code
},delayInMs);
});
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.
I am making 2 requests using for loop simultaneously when someone clicks on a button. Then I post a message to their profile; say the messages are the following :
var my_array=["Hi i am jason", "I am feeling great today"];
Above is the array and then I update the statuses using the for loop, so first it loops through the first message and then through the second message.
As I am making this request, those 2 messages are updated on their profile at the same time(maybe a delay of some ms). What I want is the delay of 2s between those 2 messages(indirectly I want the delay between the for loop indices).
So when I click on the button the first message should be updated right away and the second one after 2s.
How can I achieve this?
You can create a delay in JavaScript with setTimeout: https://developer.mozilla.org/de/docs/Web/API/WindowTimers/setTimeout
For example:
window.setTimeout(function() {
//do your second API call
}, 2000); //2 seconds delay
One way to solve this (untested, but you should get the idea):
var currentMessageId = 0;
function doAPICall() {
//do API call with my_array[currentMessageId]
currentMessageId++;
if (currentMessageId < my_array.length) {
window.setTimeout(doAPICall, 2000); //2 seconds delay
} else {
//done
}
}
You can also encapsulate the whole code in a function, so you can call it on button click. Or just set the currentMessageId parameter to zero in the else block.
Btw, prefilling the message is not allowed according to the platform policy. The user must write every single message by himself.
This is a really basic JavaScript question and probably duplicate, but I don't know the answer!
I have code as follows:
function userlist_change(myval, function_type) {
// relatively slow code involving Ajax call
// based on Ajax results, change some client-side stuff
}
$("#subjectlist").change(function() {
userlist_change($("#subjectlist").val(), 'change');
}).change();
$("#subjectlist").keypress(function() {
userlist_change($("#subjectlist").val(), 'keypress');
});
I have the problem that if the .change() event is called, the userlist_change function kicks off, and it's relatively slow. If the user changes the list again (e.g. by typing), my code waits for userlist_change to complete before restarting it with the new value.
This looks quite odd in the UI, as it can take a few seconds for anything to change client-side - and sometimes the results of the first call only appear after the user has already made a second call.
Is there any way I can interrupt any existing userlist_change process when the .change() or `keypress() event is fired?
[EDIT] What would be ideal is a simple 'kill any running functions with this name' command - is this possible? Or do I really have to fiddle around with timers?!
you can store last request time in a global variable, and store a request time in each ajax request, so that when you are just showing the result of first request, if the global last request time is greater than request, request time, you should show, other wise not. For example:
var lastRequestTime;
function userlist_change(myval, function_type,requestTime) {
// relatively slow code involving Ajax call
// based on Ajax results, change some client-side stuff
if(lastRequestTime <= requestTime){
//show
}
}
$("#subjectlist").change(function() {
lastRequestTime = new Date();
userlist_change($("#subjectlist").val(), 'change',lastRequestTime );
}).change();
$("#subjectlist").keypress(function() {
lastRequestTime = new Date();
userlist_change($("#subjectlist").val(), 'keypress',lastRequestTime );
});
You should use throttling of event. It is quite easily done with RX for JavaScript, but library is quite complicated. You can try filter value with timer.
Here is useful plugin for throttling: http://benalman.com/projects/jquery-throttle-debounce-plugin/