Asynchronous & serial-parallel process control
Features Supporting I/O Intensive and CPU Intensive Scenarios Macro Tasks & Micro Tasks CPU Control Release Timing Synchronous Task: Most statements are synchronous tasks, where CPU control is released only after the task is completed; this is known as a blocking task. console.log("Task 1"); console.log("Task 2"); console.log("Task 3"); Asynchronous Task: Tasks with delayed execution, typically I/O-intensive tasks. The asynchronous mechanism releases CPU control after starting a task and when no further computation is required. The task enters the task queue (blocking task queue). The event loop mechanism continuously checks whether the asynchronous event in the queue needs to regain CPU control. This is known as a non-blocking task. Asynchronous Operation APIs Asynchronous Timers setTimeout(func, delay) & setInterval(func, delay): During the delay, the CPU is released and the callback function (computation task) is placed in the asynchronous task queue. After the specified delay, when the main thread is free, the task is executed. These functions return an integer as the timer identifier, which can be used to cancel the timer. setTimeout(func, delay) runs the task once after the delay, while setInterval(func, delay) repeatedly runs the task at regular intervals. 1) setTimeout(func(a, b), delay[, praa, prab]) & setInterval(func(a, b), delay[, praa, prab]): These functions specify the callback function API format to accept two parameters, supporting the passing of these parameters ([, praa, prab]). To pass more than two parameters, encapsulate them in another function. 2) In both setInterval(func, delay) and setTimeout(func, delay), the this context defaults to the global environment (window), not the object that binds the method. To solve this, the method can be wrapped in an anonymous function or use the bind method. 3) A common use of setInterval is to implement polling. 4) If the execution time of the callback function is less than the delay in setInterval, it will be triggered every delay time. If the callback execution time exceeds the delay, it will still trigger every delay time (the task won't be lost), but it will wait for the previous task to finish before running the next one, which may result in concurrent execution if too many tasks accumulate. 5) Since the delay function is triggered every interval, not after each call, recursive calls with setTimeout can achieve the latter. It's also recommended to use recursion if the callback execution time exceeds the delay. 6) Debouncing: Prevent the callback from being called frequently by setting an interval between executions. 7) setTimeout(f, 0) doesn’t execute f immediately because the task is pushed to the next round of the event loop and will execute only after the current synchronous tasks are completed. 8) setTimeout(f, 0) is commonly used to adjust event execution order, for example, ensuring DOM events are triggered in the expected sequence. 9) setTimeout(f, 0) can reduce performance pressure. When multiple DOM operations are required, breaking them into smaller batches prevents the browser from being blocked by executing all of them at once. clearTimeout() & clearInterval(): Cancel the corresponding timer. 6) When calling timers consecutively, the identifiers returned by setTimeout and setInterval are sequential. You can write a function to cancel all timers based on this. let timerId1 = setTimeout(() => { console.log("This is delayed"); }, 1000); // Executes the task once after 1 second let timerId2 = setInterval(function() { console.log(2); }, 1000); // Outputs 2 every 1000 ms until the window is closed clearTimeout(timerId1); clearInterval(timerId2); Non-blocking I/O XMLHttpRequest / Fetch API: I/O operations are typically handled in the background, so they don’t block the main thread. XMLHttpRequest is the traditional API, while fetch is a more modern, Promise-based API. File API: When using FileReader, file reading is asynchronous, and the callback is triggered once the operation completes. fetch('https://api.example.com/data') .then(response => response.json()) .then(data => console.log(data)); const reader = new FileReader(); reader.onload = function() { console.log(reader.result); }; reader.readAsText(file); Promise.resolve() & Promise.reject(reason) for Sync to Async Conversion Promise.resolve() & Promise.reject(reason) execute an empty asynchronous task and use .then to push a synchronous task to the end of the current event loop, turning it into an asynchronous operation (putting it in the low-priority queue). const f = () => console.log("now"); Promise.resolve().then(f); console.log("next"); // Output: // next // now async Declared Asynchronous Function 1) An async function returns a non-Promise value, which is automatically wrapped into Promise.resolve(value). 2) If an async function throws a

Features Supporting I/O Intensive and CPU Intensive Scenarios
Macro Tasks & Micro Tasks
CPU Control Release Timing
Synchronous Task: Most statements are synchronous tasks, where CPU control is released only after the task is completed; this is known as a blocking task.
console.log("Task 1");
console.log("Task 2");
console.log("Task 3");
Asynchronous Task: Tasks with delayed execution, typically I/O-intensive tasks. The asynchronous mechanism releases CPU control after starting a task and when no further computation is required. The task enters the task queue (blocking task queue). The event loop mechanism continuously checks whether the asynchronous event in the queue needs to regain CPU control. This is known as a non-blocking task.
Asynchronous Operation APIs
Asynchronous Timers
setTimeout(func, delay)
& setInterval(func, delay)
: During the delay, the CPU is released and the callback function (computation task) is placed in the asynchronous task queue. After the specified delay, when the main thread is free, the task is executed. These functions return an integer as the timer identifier, which can be used to cancel the timer. setTimeout(func, delay)
runs the task once after the delay, while setInterval(func, delay)
repeatedly runs the task at regular intervals.
1) setTimeout(func(a, b), delay[, praa, prab])
& setInterval(func(a, b), delay[, praa, prab])
: These functions specify the callback function API format to accept two parameters, supporting the passing of these parameters ([, praa, prab]
). To pass more than two parameters, encapsulate them in another function.
2) In both setInterval(func, delay)
and setTimeout(func, delay)
, the this
context defaults to the global environment (window
), not the object that binds the method. To solve this, the method can be wrapped in an anonymous function or use the bind
method.
3) A common use of setInterval
is to implement polling.
4) If the execution time of the callback function is less than the delay in setInterval
, it will be triggered every delay time. If the callback execution time exceeds the delay, it will still trigger every delay time (the task won't be lost), but it will wait for the previous task to finish before running the next one, which may result in concurrent execution if too many tasks accumulate.
5) Since the delay function is triggered every interval, not after each call, recursive calls with setTimeout
can achieve the latter. It's also recommended to use recursion if the callback execution time exceeds the delay.
6) Debouncing: Prevent the callback from being called frequently by setting an interval between executions.
7) setTimeout(f, 0)
doesn’t execute f
immediately because the task is pushed to the next round of the event loop and will execute only after the current synchronous tasks are completed.
8) setTimeout(f, 0)
is commonly used to adjust event execution order, for example, ensuring DOM events are triggered in the expected sequence.
9) setTimeout(f, 0)
can reduce performance pressure. When multiple DOM operations are required, breaking them into smaller batches prevents the browser from being blocked by executing all of them at once.
clearTimeout()
& clearInterval()
: Cancel the corresponding timer.
6) When calling timers consecutively, the identifiers returned by setTimeout
and setInterval
are sequential. You can write a function to cancel all timers based on this.
let timerId1 = setTimeout(() => {
console.log("This is delayed");
}, 1000); // Executes the task once after 1 second
let timerId2 = setInterval(function() {
console.log(2);
}, 1000); // Outputs 2 every 1000 ms until the window is closed
clearTimeout(timerId1);
clearInterval(timerId2);
Non-blocking I/O
XMLHttpRequest / Fetch API: I/O operations are typically handled in the background, so they don’t block the main thread. XMLHttpRequest
is the traditional API, while fetch
is a more modern, Promise-based API.
File API: When using FileReader
, file reading is asynchronous, and the callback is triggered once the operation completes.
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data));
const reader = new FileReader();
reader.onload = function() {
console.log(reader.result);
};
reader.readAsText(file);
Promise.resolve()
& Promise.reject(reason)
for Sync to Async Conversion
Promise.resolve()
& Promise.reject(reason)
execute an empty asynchronous task and use .then
to push a synchronous task to the end of the current event loop, turning it into an asynchronous operation (putting it in the low-priority queue).
const f = () => console.log("now");
Promise.resolve().then(f);
console.log("next");
// Output:
// next
// now
async
Declared Asynchronous Function
1) An async
function returns a non-Promise value, which is automatically wrapped into Promise.resolve(value)
.
2) If an async
function throws an error, it returns a rejected Promise
.
3) await
can only be used inside an async
function. It pauses the execution of the function until the Promise is resolved, then returns the result. This makes the code look synchronous, but it remains asynchronous in the background.
async function exampleTask() {
return "Task completed";
}
exampleTask().then(result => {
console.log(result); // Output: Task completed
});
Asynchronous Operation Models
Callback
A manually set asynchronous task where the CPU immediately schedules tasks after releasing control.
function f1(callback) {
callback(); // After starting an asynchronous operation, the callback is immediately scheduled
}
function f2() {
// Do something...
}
f1(f2);
Event-Driven
function f1() {
setTimeout(function() {
const event = new Event('done');
document.dispatchEvent(event);
}, 1000);
}
function f2() { console.log('f2 executed'); }
document.addEventListener('done', f2); // Listen to 'done' event
f1();
In this example, document
acts as the event center. When f1
finishes, it manually triggers the done
event, and f2
is executed upon receiving the event.
Publish-Subscribe Pattern
A simple publish/subscribe system can be optimized using a singleton pattern.
const PubSub = {
subscribers: {},
subscribe: function(event, callback) {
if (!this.subscribers[event]) {
this.subscribers[event] = [];
}
this.subscribers[event].push(callback);
},
publish: function(event, data) {
if (this.subscribers[event]) {
this.subscribers[event].forEach(callback => callback(data));
}
},
unsubscribe: function(event, callback) {
if (this.subscribers[event]) {
this.subscribers[event] = this.subscribers[event].filter(cb => cb !== callback);
}
}
};
// Usage example
function f2(data) {
console.log('f2 executed, received data:', data);
}
function f1() {
setTimeout(function() {
console.log('f1 executed, publishing done event');
PubSub.publish('done', 'f1 completed');
}, 1000);
}
PubSub.subscribe('done', f2);
f1();
Promise-Based Asynchronous Operation
The async task executor initiates the asynchronous operation and either returns the result or throws an error.
const promise = new Promise((resolve, reject) => {
if (/* success */) {
resolve(value); // Success
} else {
reject(error); // Failure
}
});
async
-Wrapped Asynchronous Operations
Using async
functions to handle asynchronous tasks allows for easier error handling with try/catch
.
async function exampleTask(taskId, duration) {
console.log(`Task ${taskId} started`);
await new Promise(resolve => setTimeout(resolve, duration)); // Simulate async operation
console.log(`Task ${taskId} completed`);
}
Synchronous Tasks from Asynchronous Operations
Once an asynchronous task is started, it needs to wait for the synchronous tasks in the main thread to complete before it can be scheduled for execution. This increases the priority of asynchronous task scheduling.
Generator Synchronizing Asynchronous Tasks
Using yield
in a generator function pauses its execution until the asynchronous operation is completed.
function* main() {
var result = yield request("https://some.url");
var resp = JSON.parse(result);
console.log(resp.value);
}
async/await
Simulates Synchronous Task Steps
await
pauses the execution of an async
function until the Promise is resolved, and then returns the result. This makes the internal steps of the function execute synchronously, but the overall scheduling remains asynchronous.
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint("hello world", 50);