JavaScript Timer-Based Pseudo-Threading

Share this article

In my previous post, JavaScript Execution and Browser Limits, I described how the top 5 browsers determine when JavaScript code has run for too long and throw “unresponsive script” errors. It’s not practical to change the browser’s behavior and it may not always be possible to offload processing to the server. Fortunately, timers can help us execute long-running tasks without locking the browser.

What are timers?

JavaScript code, such as an individual function, can be set to run after a particular period of time has elapsed:
  • setTimeout(function, msec[, arg1 … argN]) runs the named function after msec milliseconds have passed. The arguments, if any, are passed to that function.
  • setInterval(function, msec[, arg1 … argN]) is similar to setTimeout except the function is called indefinitely every msec milliseconds.
Two other functions, clearTimeout() and clearInterval(), will cancel timer operations, e.g.

var timerID = setTimeout(myfunction, 500);
clearTimeout(timerID); // myfunction() will never be called
Note:
  1. setTimeout and setInterval are passed a reference to a function (there’s no parenthesis). The code setTimeout(myfunction(), 500); would run myfunction() immediately.
  2. The millisecond timings will rarely be accurate. They only specify that a function should run when the browser becomes idle after a specific period.
  3. Don’t rely on functions running in a specific order, e.g. setTimeout(f1, 50); setTimeout(f2, 50); — f2() could execute first.

Timer-based execution

Timed code isn’t run immediately, so the browser processing thread is released to perform other tasks. We can therefore split long processes into shorter chunks. As a simple example, assume we want to run the functions f1(), f2() and f3() in order:

function ProcessThread(func) {
	var ms = 20;
	setTimeout(function() {
		func.shift()();
		if (func) {
			setTimeout(arguments.callee, ms);
		}
	}, ms);
}

ProcessThread([f1, f2, f3]);
note: func.shift()() ?!
That requires a little further explanation; func.shift() removes the first item from an array and returns it. That will be reference to a function, so we add parenthesis to execute it. The statement is functionally identical to var f = func.shift(); f();
ProcessThread runs all the functions in the passed array, but waits 20ms between each. Any number of functions can be executed in sequence … assuming no individual function throws an “unresponsive script” error. However, the most time-intensive code will probably be processing large arrays of data. In my next post, we’ll write more robust code to handle that type of operation.

Frequently Asked Questions (FAQs) about JavaScript Timer and Pseudo-Threading

What is pseudo-threading in JavaScript?

Pseudo-threading in JavaScript is a technique used to simulate multi-threading. JavaScript is a single-threaded language, meaning it can only execute one task at a time. However, certain tasks, like image processing or complex calculations, can be time-consuming and block the main thread, leading to a poor user experience. Pseudo-threading helps to break these tasks into smaller chunks and schedule them to run at intervals, allowing other tasks to execute in between, thus simulating a multi-threaded environment.

How does JavaScript Timer work?

JavaScript Timer is a feature that allows you to execute a piece of code at specified intervals. It uses two main methods: setTimeout() and setInterval(). The setTimeout() method executes a function once after a specified number of milliseconds, while the setInterval() method continues to execute a function repeatedly at the specified interval until it’s stopped with clearInterval().

How can I implement pseudo-threading using JavaScript Timer?

To implement pseudo-threading using JavaScript Timer, you can use the setInterval() method. This method allows you to execute a function repeatedly at a specified interval. By breaking a large task into smaller chunks and scheduling them to run at intervals, you can simulate a multi-threaded environment. Here’s a simple example:

let i = 0;
let pseudoThread = setInterval(function() {
// perform a chunk of the task
i++;
if (i >= 10) {
clearInterval(pseudoThread);
}
}, 100);

What are the limitations of pseudo-threading in JavaScript?

While pseudo-threading can improve the user experience by preventing the blocking of the main thread, it has its limitations. Since JavaScript is single-threaded, pseudo-threading doesn’t actually allow tasks to run in parallel. It merely schedules them to run at different times. This means that if one task takes longer than expected, it can delay the execution of subsequent tasks.

How does pseudo-threading compare to actual threading in other languages like Python?

In languages like Python, which support actual multi-threading, tasks can run in parallel on different threads. This can lead to a significant performance boost for CPU-intensive tasks. However, multi-threading can also introduce complexity due to issues like race conditions and deadlocks. In contrast, pseudo-threading in JavaScript is simpler to implement and manage, but it doesn’t provide the same level of performance improvement for CPU-intensive tasks.

Can I use JavaScript Promises or async/await instead of pseudo-threading?

Yes, JavaScript Promises and async/await are modern features that provide a more elegant way to handle asynchronous operations. However, they don’t provide a solution for CPU-intensive tasks that can block the main thread. For such tasks, pseudo-threading can still be a useful technique.

How can I stop a pseudo-thread in JavaScript?

You can stop a pseudo-thread in JavaScript using the clearInterval() method. This method stops the repeated execution of the function specified in setInterval(). You need to pass the ID value returned by setInterval() to clearInterval() to stop the pseudo-thread.

Can I use pseudo-threading in JavaScript for web workers?

Yes, pseudo-threading can be used in conjunction with web workers to achieve better performance. Web workers run scripts in the background, separate from the main thread, allowing for more CPU-intensive tasks. Pseudo-threading can be used within a web worker to break down tasks and prevent blocking.

What are some practical applications of pseudo-threading in JavaScript?

Pseudo-threading in JavaScript can be used in various scenarios where a task could potentially block the main thread and degrade the user experience. This includes tasks like image processing, complex calculations, data processing, and more.

Are there any libraries or frameworks that can help with pseudo-threading in JavaScript?

While JavaScript itself provides the basic tools for pseudo-threading (like setInterval()), there are libraries like async.js and frameworks like AngularJS that provide more advanced features for managing asynchronous operations. However, these tools don’t specifically target pseudo-threading and may not be suitable for all use cases.

Craig BucklerCraig Buckler
View Author

Craig is a freelance UK web consultant who built his first page for IE2.0 in 1995. Since that time he's been advocating standards, accessibility, and best-practice HTML5 techniques. He's created enterprise specifications, websites and online applications for companies and organisations including the UK Parliament, the European Parliament, the Department of Energy & Climate Change, Microsoft, and more. He's written more than 1,000 articles for SitePoint and you can find him @craigbuckler.

javascript
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week
Loading form