I want to patch the alert object in the browser, to show additional text, but I need to await some data to show the necessary content in the alert. However, I can't postpone the alert call.
Also, I don't know about a way to close the alert and show another alert without a user action (if it exists, it can solve my problem too).
So, I have to await some data, but I can't break the alert behavior, which is blocking execution of the code.
To await a response, I can do something like this:
var start = performance.now();
while(true) {
var time = performance.now() - start;
if (time >= 3000) break;
}
console.log('done');
But instead of checking the timer, I will check some data.
This way should work, but this is terrible for performance, because it is the opposite to alert which is just freezing the thread and does nothing until the close dialog, and we'll load the CPU with useless work.
Is it possible freeze a thread to be more energy efficient?
I have to freeze the thread until I get some data from a worker.
Why is promise not solving your problem?
Promises is not blocking a main thread, so this is not reproducing the behavior of alert which I need.
The blocking thread is not user friendly and it's not that you need to await some data
I know about it, and this note is fair enough to development web pages and applications.
But this case is special. I develop a feature for a
browser extension, to translate alerts. The browser extension must not modify the behavior of the page. So when a web site is calling alert, the thread must be freeze. The browser extension must not postpone an alert call to avoid unexpected behavior on the page.
You can see the feature explained here: Feat: Implement optional translation of alerts and console logs #102
The only way I can think of to "block" without consuming CPU this would be to make a synchronous XMLHttpRequest (which are deprecated because blocking is not user-friendly). You'll need to set up a server that can read the payload of the request and reply after the specified amount of time.
const xh = new XMLHttpRequest();
xh.open('GET', urlToYourServer, false);
xh.send('3');
where that '3' is the request body that the server parses (and responds after 3 seconds).
That said, you should not do this - it's a very inelegant and user-unfriendly approach. It'll stop any other action (including browser repainting and other requests) from occurring while this is going on. Better to properly wait for whatever you need (whether that's through a .then of a Promise, or a callback, or something else) - but without more context in the question, how exactly to accomplish this is unclear.
Related
I setState to cause a loading spinner to appear and then call a long running operation. The operation blocks the UI, so the spinner doesn't appear. My workaround is to delay the operation by 500ms with setTimeout, so the spinner has time to appear.
Is there a better way?
I even wrote a helper function to do it:
async runAsync(message, asyncFn) {
const loadingId = this.add(message)
await _.sleep(50); // Let react update
await asyncFn();
this.remove(loadingId)
}
It's pretty suspicious for there to be a task that's expensive enough to reliably block rendering on the client. Sometimes a case can be made for it, but in most circumstances there are better approaches.
Ideally, these sorts of expensive operations would be offloaded to your server instead, if at all possible. Instead of the client doing it themselves, have the client make a request to the server, have the server perform the work, and then send the result back to the client. (If you can easily notice a delay on the computer you use for development, someone opening the website on even worse hardware - such as a phone - would have a much worse experience.)
If the above isn't possible, the other main possibility to consider would be to spawn a separate environment on the client, and perform the work in that environment - which will not interfere with rendering (such as the display of a loading spinner) on the original webpage. This can be accomplished with a web worker.. Make a request to the worker while creating the loading spinner, and then the spinner will appear immediately (and animate) while waiting for the worker to finish its processing. Then, have the worker send a message back to the parent page containing the required data.
I'm working on a simple chat implementation in a function that has an ajax call that invokes a setTimeout to call itself on success. This runs every 30 seconds or so. This works fine, but I'd like a more immediate notification when a message has come. I'm seeing a lot of examples for long polling with jQuery code that looks something like this:
function poll()
{
$.ajax(
{
data:{"foo":"bar"},
url:"webservice.do",
success:function(msg)
{
doSomething(msg);
},
complete:poll
});
}
I understand how this works, but this will just keep repeatedly sending requests to the server immediately. Seems to me there needs to be some logic on the server that will hold off until something has changed, otherwise a response is immediately sent back, even if there is nothing new to report. Is this handled purely in javascript or am I missing something to be implemented server-side? If it is handled on the server, is pausing server execution really a good idea? In all of your experience, what is a better way of handling this? Is my setTimeout() method sufficient, maybe with just a smaller timeout?
I know about websockets, but as they are not widely supported yet, I'd like to stick to current-gen techniques.
Do no pause the sever execution... it will lead to drying out server resources if lot of people try to chat...
Use client side to manage the pause time as you did with the setTimeout but with lower delay
You missed the long part in "long polling". It is incumbent on the server to not return unless there's something interesting to say. See this article for more discussion.
You've identified the trade-off, open connections to the web server, therefore consuming http connections (i.e. the response must block server side) vs frequent 'is there anything new' requests therefore consuming bandwidth. WebSockets may be an option if your browser base can support them (most 'modern' browsers http://caniuse.com/websockets)
There is no proper way to handle this on the javascript side through traditional ajax polling as you will always have a lag at one end or the other if you are looking to throttle the amount of requests being made. Take a look at a nodeJS based solution or perhaps even look at the Ajax Push Engine www.ape-project.org which is PHP based.
I need to execute an action of a controller when a user leave a page (close, refresh, go to link, etc.). The action code is like:
public ActionResult WindowUnload(int token)
{
MyObjects[token].Dispose();
return Content("Disposed");
}
On window download I do Ajax request to the action:
$(window).unload(function ()
{
$.ajax({
type: "POST",
url: "#Url.Action("WindowUnload")",
data: {token: "#ViewData["Token"]"},
cache: false,
async: true
});
//alert("Disposing.");
})
The above ajax request does not come to my controller, i.e., the action is not executed.
To make the code above to work I have to uncomment the alert line, but I don't want to fire alert on a user.
If I change async option to false (alert is commented), then it sometimes works. For example, if I refresh the page several times too fast then the action will not be executed for every unload.
Any suggestions how to execute the action on every unload without alert?
Note, I don't need to return anything from action to the page.
Updated: answers summary
It is not possible reliably to do request on unload, since it is not proper or expected behavior on unload. So it is better to redesign the application and avoid doing HTTP request on window unload.
If it is not avoidable, then there are common solutions (described in the question):
Call ajax synchronously, i.e., async: false.
Pros: works in most cases.
Pros: silent
Cons: does not work in some cases, e.g, when a user refreshes the windows several times too fast (observed in Firefox)
Use alert on success or after ajax call
Pros: seems to work in all cases.
Cons: is not silent and fires pop up alert.
According to unload documentation, with async: false it should work as expected. However, this will always be a bit shaky - for example, user can leave your page by killing/crashing the browser and you will not receive any callback. Also, browser implementations vary. I fear you won't get any failproof even.
HTTP is stateless and you can never get a reliable way to detect that the user has left your page.
Suggested events:
Session timeout (if you are using sessions)
The application is going down
A timer (need to be combined with the previous suggestion)
Remove the previous token when a new page is visited.
Why does this need to happen at all?
From the code snippet you posted you are attempting to use this to dispose of objects server side? You are supposed to call Dispose to free up any un-managed resources your objects are using (such as Database connections).
This should be done during the processing of each request. There shouldn't be any un-managed resources awaiting a dispose when the client closes the browser window.
If this is the way you are attempting this in the manner noted above the code needs to be reworked.
Have you tried onbeforeunload()?
$(window).bind('beforeunload', function()
{
alert('unloading!');
}
);
or
window.onbeforeunload = function() {
alert('unloading!');
}
From the comment you made to #Frazzell's answer it sounds like you are trying to manage concurrency. So on the chance that this is the case here are two common method for managing it.
Optimistic concurrency
Optimistic concurrency adds a timestamp to the table. When the client edits the record the timestamp is included in the form. When they post their update the timestamp is also sent and the value is checked to make sure it is the most recent in the table. If it is, the update succeeds. If it is not then someone else got in sooner with an update so it is discarded. How you handle this is then up to you.
Pessimistic concurrency
If you often experience concurrency clashes then pessimistic concurrency may be better. Here when the client edits the record a flag is set on that row to lock it. This will remain until the client completes the edit and no other user can edit that row. This method avoids users loosing changes but add an administration over head to the application. Now you need a way to release unwanted locks. You also have to inform the user through the UI that a row is locked for edit.
In my experience it is best to start with optimistic concurrency. If I have lots of people reporting problems I will try to find out why people are having these conflicts. It maybe that I have to break down some entities in to smaller types as they have become responsible for doing too many jobs.
This wont work and even if you are able to somehow make it work it will give you lots of headaches later on, because this is not how the browser/HTTP is supposed to be used. When the page is unloading (in browser) the browser will call the unload event and then unload the page (you cannot make it wait, not even my making sync ajax calls) and in case the call was going on and the browser after executing the code unload the page, the call will also get cancelled and thats why you see the call on server sometimes and sometimes it doesn't work. If you could tell use why you want to do this we could suggest you a better approach.
You can't. The only thing you can do is prompt the user to stay and hope for the best. There are a whole host of security concerns here.
From javascript I'm calling a web method. With IE, if I pass a huge parameter to that web method, an alert "Stop running this sciprt? A script on this page is causing internet explorer to run slowly" pops up.
Is it possible to handle the click on the "Yes" button, so that if the user decides to cancel the script execution I can run some alternative script (in this case, my "alternative" script consists in closing some progress bar I popup just before running the long time script).
I have seen many posts explaining how to prevent this alert from being displayed, but I don't want to stop the alert from being displayed: I just want to be able to handle the case in which the user decides to stop the script execution.
I've dealt with this before on an internal app where they didn't care how long it took the browser to crunch the numbers, they just didn't want to have to click the prompt.
The key is to break the work down into relatively predictable chunks of work (predictable in terms of CPU time) and run them on a setInterval like:
function doWork(begin, end) {
// Some chunk of what your worker function normally does from begin to end
if (actualEnd < end) // Nothing left to do
clearInterval(Interval);
}
var Interval = setInterval(doWork, 15);
This prevents the IE prompt from appearing (or Chrome from presenting the "Freeze" dialog). The next step is to add some code that lets the user skip it entirely; if the amount of work is known at the beginning, ask them right away. If not, start processing and after n chunks ask them if they'd like to do the cheaper function.
There are 2 other options for getting this much work done:
Look ahead as to how much work there is to be done, and if it's a lot, pass it to the server (this unfortunately means writing your JS again on the server; of course, you could use a server engine that runs Javascript to save yourself some coding).
Use background workers from Google Gears/HTML5
Finally, if you are doing this much work on demand, there are probably speed-up opportunities in the work you're performing - the data could be indexed beforehand on the server to make the calculations faster/simpler, things like that. But I don't know what you're calculating.
Is is possible to intercept browser messages such as:
Firefox:
A script on this page may be busy, or
it may have stopped responding. You
can stop the script now, open the
script in the debugger, or let the
script continue.
I.E.
A script on this page is causing your
web browser to run slowly. If it
continues to run, your computer might
become unresponsive.
These messages are occuring due to the page having alot of javascript/jquery activity.
I appricate that the fact the these messages are appearing in the first place indicate a wider problem, but is there a way of intercerping this message/situation on the client side so that a more user friendly message can be shown?
No there's no way to do this, imagine a malicious user writing a script which slows down your browser until is completely unusable, now the "Slow Script" Warning may come to the rescue, but what if he could intercept it and prevent it from being shown?
You'll need to find a solution for the underlying problem, that is, in case that you're doing a lot of calculations(which I suppose you do), you need to split those of into chunks, put them into a queue and process them either asynchronously(if possible) or in order, but with a small timeout in between.
In pseudo code it may look like this:
var queue = []; // put your functions or the data in here
function() processQueue{
if (queue.length > 0) {
var item = queue.shift() // pop of the first item of the queue
item(); // call the function, or in case of data pass it to th processing function
setTimeout(processQueue, 100); // wait 100 ms before processing the next chunck
}
}
setTimeout(processQueue, 0);
No, there is no way to intercept these messages, they are are there at a lower level in the engine to protect the user. Instead look at what's taking so long, optimize as much as possible...possibly breaking your work up into chunks that have gaps in processing so you don't trigger the messages.