Is this a React anti-pattern? - javascript

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.

Related

How to lock thread in javascript energy efficient?

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.

How do I make a loading page while I am processing something in the backend with Django?

I have a main view function for my application. After logging in successfully this main view method is called and is expected to render the template.
But I have to perform some calculations in this view method [I am checking certain conditions about the user by making facebook graph api request.]
Thus it takes 2~4 seconds to load.
How do I show this loading scene since the template is rendered by return statement and thus is executed only when the process is complete.
Should I make 2 views , one for showing loading and the other one for calculating and keep making AJAX request to other view method to check if the process is complete or not ?
You should indeed make two views, one to only return the page showing the loading UI and one to perform the long task.
The second view will be called using an AJAX request made from the "loading" page. The response from the AJAX request will notify your "loading" page that it is time to move on.
You need to make sure the AJAX request's duration won't exceed the timeout of your server (with ~10 seconds, you should be fine).
You need to run your Graph API requests in a task executed asynchronously, allowing you to return a HttpResponse without waiting for the task to finish.
Celery will allow you to do just that.
You then need a way to notify your client that the asynchronous task has finished.
I see two ways to do that:
Making AJAX requests at regular intervals to a view that will check if the task is finished.
Using WebSockets.
The first approach is the simplest but has the drawback of making a lot of useless requests and of being less reactive.
Using WebSockets on the other side will require more configuration as an external app is required (ex: django-socketio or swampdragon).
If it is the only place where you need notifications from server to client, using WebSockets seems to be overkill.

Asynchronous operation in blocking chrome.webRequest.onBeforeSendHeaders listener

I'm developing a Chrome extension, and have run into an issue due to developing against a mixture of synchronous and asynchronous apis.
chrome.webRequest.onBeforeSendHeaders.addListener(function(details) {
//code that modifies details.requestHeaders
//..
return {requestHeaders: details.requestHeaders};
},
{urls: ["<all_urls>"]},
["blocking", "requestHeaders"]
Inside the listener function I want to fetch data from IndexedDB and modify the request headers based on this data. IndexedDB only has an asynchronous API, while the contract for the listener requires it to be synchronous.
Any ideas how I could solve this problem?
A DB call is generally too expensive. That said, here is one idea off the top of my head (which might be horrible):
Keep an in memory cache of most frequently used data. Use some type of simple data structure like a Map.
Pre-populate the map when the app loads with whatever data is most likely to be needed. Do this when the extension background page loads.
Periodically update the cache's contents during the runtime lifecycle when appropriate. Do this from the app's background page, using an alarm to trigger an update on a schedule. Register the alarm on background page load/app startup.
Query the in memory map in onBeforeSendHeaders. Map lookups are synchronous and fast. If the lookup works, great. If it fails, think of an error handling mechanism (if you call this an error).
When a cache miss occurs, trigger an async call (for which you don't need to wait to resolve) that eventually logs the cache miss to another data structure. The same other structure you use for the code that periodically updates the map.
When a cache hit occurs, trigger an async call that increases the chance the value remains in the map, and slightly decrease the chance for other items in the cache (perhaps that is implicit in the increase).
Don't forget to prune the cache in the background cache update for items that are no longer likely
Experiment with a cache size that yields decent performance and reasonably memory usage.
That being said, you would need to think of the user experience in the event of a cache miss. Maybe supply a default parameter, or a placeholder value of some sort that notifies the user of the miss somehow. It kind of depends on how you want the app to work and what the app does, which you did not state.
Oh, derp, and consider using localStorage as the in memory map... Duh.

Long Polling: How do I calm it down?

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.

Intercepting browser slow script messages

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.

Categories

Resources