-
Notifications
You must be signed in to change notification settings - Fork 0
zThreader overview
This page documents the API available to zThreader and zThread-usage. First up an explanation : a zThread is basically a JS class that can separate a heavy operation into several iterations, which are executed whenever the CPU has free resources, this to ensure that an application remains responsive and smooth during heavy calculations and to omit the dreaded script timeout that can lead to browser crashes! You have read the rationale in the README file and are on board with giving this a whirl.
zThreader is a cross platform method that divides script execution evenly amongst heavy operations, making sure there is enough CPU resources left for updating the screen and running other (asynchronous) script operations. Additionally, you have the benefit of creating Java / C-style daemons (i.e. repeated operations that never finish during the application lifetime) without halting all other script execution!
Note : if you desire your custom thread to be finite and used only for performing a single (but heavy!) calculation: it is important to realize that it is up to you to write your operation in such a manner that it can be executed in separate iterations (consider having to do a loop of up to 15,000,000 cycles, you'd have to write the logic so that you can break the loop and continue where you left off). The zThread and the zThreader manager will take care of executing the code whenever the processor is idle. It is also important to notice that a zThreaded operation will run slower than running it synchronously in one go, but by writing an efficient iterated function, the difference can be negligible, and the benefit of having a responsive, smooth application makes it worth the effort!
A static class that acts as the manager that delegates work over individual "threads". Each zThread will automatically register itself into (and out of) the zThreader when required.
The zThreader uses requestAnimationFrame
which basically means the browser sends a signal whenever it is ready to perform another set of operations (for instance: if you were to switch to another tab in the browser, the application running in the previous tab is suspended as no requests will be fulfilled by the browser). This is essentially to use less processor resources, save battery life on your tablet/phone and to ensure no animations keep running in animated applications). zThreader uses requestAnimationFrame to manage execution of the registered threads. By setting the zThreader priority
, you basically specify a percentage of CPU resources which are allotted to executing the individual thread operations. When the allotted percentage has been spent on running threads, the remainder is free for the browser to continue executing other script operations / render the screen.
When an individual thread has finished all its required operations, it will automatically remove itself from the zThreader manager, which in turn will dedicate more time to the remaining threads, speeding up their individual processes, until they have all finished.
If there are no threads registered (or all have completed their process), zThreader will unregister itself (cancelAnimationFrame
) until it is needed again.
init( priority: number, fps: number )
where priority is a percentage (in the 0 to 1 range) which dictates how much % of the CPU will be used upon each thread execution. Even a 100 % (1) allocation will keep the application more responsive as it would be in non-threaded execution. Lower values ensure smooth animations will retain their smoothness.
fps is an optional value (defaults to 60) and implies "frames per second", which will make more sense if your application also uses strictly timed animations (for instance: a game). Syncing this to the animations ensures an even distribution of CPU resources between running the threaded functions and the animation rendering.
Running this method once is the minimum you need to actually use zThreader within your application. The following public methods are all accessed by individual zThreads:
add( thread: zThread ): boolean
Invoked by given thread when its run-method is invoked. This adds a new zThread to the thread list, allowing zThreader to manage it (and thus execute its operations when resources are available). If this is the first addition of a Thread, the zThreader will automatically start listening to allotted CPU time.
remove( thread: zThread ): boolean
Invoked by given thread when it has completed its operations. This removes the zThread from the thread list. If this leads to an empty thread list, the zThreader will automatically stop listening to allotted CPU time, remaining idle.
has( thread: zThread ): boolean
Returns a boolean value whether given thread is currently being managed by the zThreader.
stop(): void
Removes all registered threads from the zThreader and stop listening to allotted CPU time, basically flushing the existing queue.
getAmountOfThreads(): number
Returns the number of actively running threads.
setPriority( percentage: number ): void
Where percentage is a numerical value between 0 - 1 to dictate the amount of CPU resources we'd like to distribute to the zThreader.
A zThread is basically a class instance. You can choose to extend the class for your custom thread, or you can simply use the base zThread and specify your custom execution handler as a custom zThread should ideally only contain a custom executeInternal()
-function body where your custom operations are executed. A zThread should be instantiated and its run()
-method must be invoked, after which it can be ignored as invoking run()
will ensure it will register itself into the zThreader who will execute it as it sees fit, and removes the thread when it completes. As such you need to maintain no reference to the zThread so it will be garbage collected automatically and memory can be freed when it has completed its life cycle.
zThread({ completeFn?: () => void, executionFn?: () => boolean })
Constructs a new zThread instance. executionFn is an optional Function reference which will be executed once for each iteration of the threading process. This can only be undefined when you create a custom class that extends the zThread prototype (be sure to override its executeInternal()
-method). Read up on the documentation of the executeInternal()
-method to understand the behaviour tied to this function. completeFn is an optional Function reference which will be executed once the zThread has completed its operation, you can use this to tie together (asynchronous) application logic that is dependent upon the zThread operation results.
run(): void
Will register the thread into the zThreader, which in turn will execute its operations when appropriate.
stop(): void
Will halt the threads execution and remove it from the zThreader. Should be used when it is feasible to dispose an unfinished thread.
pause(): void
Halts a threads execution until unpause()
has been invoked. This will leave the thread inside the zThreader, but will divide its allocated time over the remaining threads.
unpause(): void
Resumes a paused threads execution.
execute( allocatedTime: number ): boolean
Invoked by the zThreader when the CPU has allotted time for this thread, this method shouldn't be invoked manually. Your custom zThread extension mustn't override this method, but rather override executeInternal()
.
sleep( duration: number ): void
Can be invoked to temporarily suspend a threads execution (for the given duration period in milliseconds). During the timeout the thread will not execute its operations and the zThreader will increase allotted time for the remaining (active) threads.
isExecutable(): boolean
Returns a boolean indicating whether the thread can be executed (if sleep()
or pause()
have been invoked it should be suspended and thus return false). This is queried by the zThreader prior to execution.
executeInternal(): boolean
This method must be overridden by your custom zThread, - if you were creating a custom class extending the zThread prototype - (otherwise you would have provided executionFn
to the base zThread constructor. It is here where your operations are executed. This method must return a boolean value which is true when the thread has finished all its operations and can be removed from the zThreader. If the thread still hasn't finished, it must return false to instruct the base execute()
-method that the thread must remain registered in the zThreader, so it can continue to execute on the next available time slot. If your thread never finishes but acts as a permanent daemon, simply return false always.
Note that if your threads custom operation is loop-based (i.e. uses iterations and thus: can finish), you can use the protected _iterations
-property of the zThread class (which is always 0 once it starts running) to monitor progress. For instance: if you are to perform a calculation over a maximum of 15 million iterations, you can query and increment _iterations
inside this function body to "continue where you left off" in between adjacent executions invoked by the zThreader.
handleComplete(): void
Automatically invoked by the zThread base execute()
-method once its operations have completed. This will unregister the zThread from the zThreader and invoke the registered callback (if there was one). After completion the zThread can be garbage collected (unless strong references to it remain within your application).