I'm planning on writing some code for encrypting files in javascript locally. For large files and large key sizes, the CPU usage (naturally) is pretty high. In a single script design, this often hangs the browser until the task is complete.
In order to improve responsiveness and allow users to do other things in the mean time I want to try make the script 'friendlier' to the user's PC. The encryption process will be reading a file as a binary string and then encrypting the string in chunks (something like 1KB/chunk - needs testing). I want to try and user HTML5-based workers to make the whole thing as incremental as possible. Something like:
Spawn worker
Send worker a binary data chunk
Worker completes encryption, passes back new chunk
Worker dies.
This might also help with multicore processors, by having multiple workers alive at once.
Anyway, has anybody looked at deliberately slowing down a script in order to reduce CPU usage? Something like splitting the worker's encryption task into single operations, and introducing a delay between them.
Interval timer callback every 100ms (example).
Is worker busy?
Yes - Wait for another interval
No - Start encrypting the next letter
Advice/thoughts?
Does anyone have experience using workers? If you seperate the main UI from intensieve work by making it a worker, does the responsiveness increase?
This doesn't utilize anything HTML5, but here's an example for calling a function every N milliseconds, assuming you can determine an appropriate wait time. Basically, I'm trying to help you by showing you a way to enforce stalling some amount of time before doing more processing.
function doSomething(){
clearTimeout(timeout);
// do your "expensive" processing
// ...
// decide the job is done and return here or else
// call doSomething again in sleepMS milliseconds
timeout = setTimeout(doSomething,sleepMS);
}
var timeout;
var sleepMS = 1000;
doSomething();
EDIT
changed last line from
var timeout = setTimeout(doSomething,1000);
to just this
doSomething()
EDIT 2
Changed 1000 to sleepMS in setTimeout call, duh :)
Related
I'm reading a bit about micro tasks and such, because at the moment I have a project that is poorly optimized and some tasks make the UI hang.
I've solved 95% of that by using a (Service) Worker for the heaviest tasks. But there's still some code that just has to be on the main thread and I'm wondering what the best way is to optimize that code.
I basically have 2 wishes:
I want a function to wait a little bit before executing, just enough to let the browser do any necessary UI drawings / changes.
But after that, I do want that function to execute as soon as possible. If I can prevent it, I don't want the task to be put at the very end of the browser's task queue. The reason for this is because the function changes the value of a variable and other functions down the line would benefit from having the latest update of the value of that variable.
After reading about micro tasks, I'm not sure if they're the right tool for the job. Because as far as I understand, the browser's decision on when to run a microtask has not so much to do with the UI, but more with what other macro tasks are on the task queue.
These are the alternatives that I've been able to find:
setTimeout() with a timeout of 0, I've read that the browser will automatically increase the time-out if it needs to.
requestAnimationFrame(), but that seems to always wait at least 1/60th of a second. If the UI is done sooner than that, then I'd want my function run sooner than that.
requestIdleCallback() sounds perfect, except that it's not supported by all browsers.
using new MessageChannel() to send an empty message from one port to the other; then executing the task when the 2nd port receives the message. The only reason I'm considering this one is because apparently Facebook uses it in React to queue a task in the browser. On Node React uses setImmediate(), but since that doesn't exist in the browser, apparently Facebook's developers thought this was the best alternative. And because I'm assuming they're cleverer than me, I think there must be something to it, right?
If web workers are an option (see comlink or do vanilla implementation) otherwise see the rest of my answer.
Considering your wish #1, I understand that you want consistent frame rate i.e. use only ideal time and next critical UI task should supersede your task.
All the options that you have listed out will not work out if the task runs longer than time for next Paint. Once the task is running it will have to end before browser can do anything else. So the problem is not with scheduling per say but preempting the task for more critical UI tasks.
In terms of scheduling both setTimeout and requestIdleCallback will not satisfy your wish #2 as, setTimeout will push new task at the end of the queue and requestIdleCallback (being worse of two in terms of priority) will wait for all the tasks to complete.
There is no straight forward way to automatically preempt a task in javascript as of now (to best of my knowledge). Even libraries like React can cause UI throttling if pushed hard enough.
Solutions that we have at hand.
Recursive SetTimeout.
Generator functions with some form of scheduling.
In both scenario you will be responsible for breaking down the task in smaller chunks that can "hopefully" complete before next UI paint.
Both work in same fashion pretty much with only difference being that you will need to chain tasks in setTimeout and in generator you can yield. The generator approach is way better in my opinion in terms of syntax as you will just need to add yield statement at different places. Not ideal but better.
Generator Example.
function* task = () => {
let i = 0;
while (true) {
i = i+1 % 10;
yield;
}
}
const callback = () => {
task.next();
setTimeout(callback, 0);
}
setTimeout(callback, 0);
P.S. Personally I wish there was a simple solution, I've looked for one for a long time. Let me know if this answers your question, if you have any doubts or you find anything interesting around this topic.
I am working in real time trading application using Node.js(v0.12.4) and Socket.io(1.3.2). In that, I am facing some time delay nearly (100ms) when the response emitting from Node.js to GUI(Socket.Io).
I don't have a clue why the time delay is there while emitting data from Node.js to GUI (Socket.IO).
This happening in Production Site. And we tried to debug this in production server location also because of network latency. But same result.
Please anyone help me on this?
One huge thing to note before doing the following.
When calculating timing from back-end(server side) to front end
(client side) you need to run this on the same computer that uses the same
timing crystal.
quartz crystal-driven timing even on high quality motherboards deffer
from one another.
If you find no delay when calculating time delay from back-end(server side) to front end (client side) on the same pc then the delay you originally found was caused by either the network connection or the deference in the motherboards timing crystals. Which would eliminate Node.js and Socket.io as the cause of the time delay.
Basically you need to find out where the delay is happening before you can solve the problem.
What you need to do is find out what is causing the largest performance hit in your project. In order to do this you will need to isolate the time each process takes. You also need to measure the time delay from the initial retrieval of the data to the release of the data. Then measure the time delay of each function, method and process. Try to isolate the problem. You need to ask what is taking the most time to do?
In order to find out where your performance hit is coming from you need to do the following.
Find out how long it takes for your code to get the information it needs.
Find out how long each information manipulation process takes before it sends out the data i.e function/methods...
After the information is sent out find how long it takes to get the information to the client side and load.
Add all of the times up and make sure it is equal to your performance delay in order to insure you have all the data you require to isolate the performance leak.
Order every method, function, process… by its time delay most time consuming to least time consuming. When you find what processes are causing the largest delays you will then be able to fix the problem... Or at least explore tangible solutions...
Here are some tools you can use to measure the performance throughout your code.
First: Chrome has a really good tool that lets you see the performance of each piece of executed code.
https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/timeline-tool?hl=en
https://developer.chrome.com/devtools/docs/timeline
Second: performance-now node package. You can use it for dev performance testing.
Third: Stack overflow post on measuring time/performance in js.
Fourth: you can use things like console.time()
https://nodejs.org/api/console.html
https://developer.mozilla.org/en-US/docs/Web/API/Console/time
https://developer.chrome.com/devtools/docs/console-api
I have found out that time delay where it is happening.
Once, I have emitted the data from Client Socket to Node, I will show the some alert message ("Data Processed"). The alert message taking time to render in GUI.
This alert message blocking the response data from the Node to Socket.
Thanks for your help Guys.
I have read several posts about doing "sleep" or "wait" in Javascript. However, they all use client side Javascript. I need to do this in a Scheduled NetSuite SuiteScript. I ahve tried setTimeout() and it tells me it cannot find the function (as well as window.setTimeout()).
If I have to do an infinite loop with an if condition that gives me the delay I want, i will do that but it is less than ideal. I want to know if there is a simple "sleep" or "wait" kind of way of doing this to delay code from executing.
My purpose is because my code deletes records. In my current setup, if 2 of these records are deleted too close to one another NS throws "unexpected error" and stops. if there is a long enough pause in between, then it works. I am trying to automate this so i don't sit here deleting records all day.
The posts I have checked so far:
How to create javascript delay function
JavaScript.setTimeout
JavaScript sleep/wait before continuing
What is the JavaScript version of sleep()?
Mine is not a duplicate to any of those as they all assume Client side and are not specific to NetSuite SuiteScript. Thanks!
Doing a loop based wait might be an overhead, as at times NetSuite might warn of number of script statement.
Another way of doing a sleep can be using nlapiRequestURL() and writing a service on your web server, as it is blocking and synchronous on server side. You can write a HTTP service and in your web server do the sleep job and then respond to the client.
If you are deleting records in a scheduled script then those run serially. Have you tried wrapping the nlapiDeleteRecord call in a try-catch?
If you are getting an error then is a User Event or workflow script running and throwing the error?
As far as a wait I've done the following. It runs the risk of throwing a too many instructions error but avoids a database call that would eat governance. If you can find an nice API call with 0 governance cost that eats some time that would be better but this worked well enough for me.
function pause(waitTime){ //seconds
try{
var endTime = new Date().getTime() + waitTime * 1000;
var now = null;
do{
//throw in an API call to eat time
now = new Date().getTime(); //
}while(now < endTime);
}catch (e){
nlapiLogExecution("ERROR", "not enough sleep");
}
}
I have a 'for' loop wich have to loop around 10000000000 times so that i get the disered result.
However, it ends up all the time freezing the browser ...
It's not like that 'for' is working infinitly but as i told, it's very long
Is there some way to solve my problem with javascript or i should use another language ?
In a compiled language and if you do virtually nothing in the loop, you can achieve 1,000,000,000 iterations a second on a desktop processor. So your loop would take 10 seconds.
If your Javascript environment is interpreted (and not compiled), you probably won't get more than 10,000,000 iterations and your loop will take 1000 seconds (16 minutes).
If you additionally have somewhat more expensive operations within the loop (and Javascript is likely to allocate memory for simple operations, which is expensive), you're in the order of 1,000,000 iterations per seconds and your code takes 10,000 seconds (close to 3 hours).
You might want to think about a better algorithm...
The issue that you are seeing is because javascript is single threaded in the browser. Your for loop is holding on to the thread for the entire time that it is running. The problem is that this thread also handles interactions with the interface. There may be other possibilities, but the two ways that I can think of to fix this would be:
Use a Web Worker (docs), this solution will not work for older browsers though
If possible, break your loop into smaller chunks that can be ran using setTimeout. After each chunk is processed, use setTimeout to schedule the next chunk to be processed in say 100ms. You will need to play with the numbers, but that should free up the thread so that it can respond to events. This will make the calculation take longer but should make it so the browser doesn't freeze up.
Don't do it. To run this kind of Javascript code in a browser makes no sense. If you really want to do this on the client side, you should consider writing some kind of browser extension, where you have more control on the CPU and local storage.
You might want to separate that loop in smaller chunks and run them sequentially, with an appropriate progress system. If you are talking about a loop, a multithreaded system will not help you, assuming the result n+1 is based on the n result.
Consider using a server-side script with a queue or job mechanism and just push notifications to the client. As Teemu said, the time (even in a fast paced situation) is huge.
My app's framework is built around collapsing backbone models sending the data via websockets and updating models on other clients with the data. My question is how should I batch these updates for times when an action triggers 5 changes in a row.
The syncing method is set up to update on any change but if I set 5 items at the same time I don't want it to fire 5 times in a row.
I was thinking I could do a setTimeout on any sync that gets cleared if something else tries to sync within a second of it. Does this seem like the best route or is there a better way to do this?
Thanks!
i haven't done this with backbone specifically, but i've done this kind of batching of commands in other distributed (client / server) apps in the past.
the gist of it is that you should start with a timeout and add a batch size for further optimization, if you see the need.
say you have a batch size of 10. what happens when you get 9 items stuffed into the batch and then the user just sits there and doesn't do anything else? the server would never get notified of the things the user wanted to do.
timeout generally works well to get small batches. but if you have an action that generates a large number of related commands you may want to batch all of the commands and send them all across as soon as they are ready instead of waiting for a timer. the time may fire in the middle of creating the commands and split things apart in a manner that causes problems, etc.
hope that helps.
Underscore.js, the utility library that Backbone.js uses, has several functions for throttling callbacks:
throttle makes a version of a function that will execute at most once every X milliseconds.
debounce makes a version of a function that will only execute if X milliseconds elapse since the last time it was called
after makes a version of a function that will execute only after it has been called X times.
So if you know there are 5 items that will be changed, you could register a callback like this:
// only call callback after 5 change events
collection.on("change", _.after(5, callback));
But more likely you don't, and you'll want to go with a timeout approach:
// only call callback 30 milliseconds after the last change event
collection.on("change", _.debounce(30, callback));