Skip to content

tsukiy0's blog

Asynchronous JavaScript

March 12, 2018

Event Loop

JavaScript executes on a single main thread, but leverages an event loop to offload and manage tasks without blocking.

Example setTimeout

const callback = () => {
console.log("hello");
}
setTimeout(callback, 1000);
sequenceDiagram autonumber CallStack->>EventTable: [Timeout] [Callback] EventTable->>EventQueue: [Callback] Note over EventTable: [Timeout] expires loop CallStack.length === 0 EventQueue->>CallStack: [Callback] end

Callbacks

Series

const task1 = () => {
setTimeout(() => {
console.log(3);
task2();
}, 1000);
}
const task2 = () => {
setTimeout(() => {
console.log(4);
}, 2000);
}
console.log(1);
task1();
console.log(2);

Parallel

let tasks = 2;
const sync = () => {
tasks--;
if (tasks === 0) {
console.log(5);
}
}
const task1 = () => {
setTimeout(() => {
console.log(3);
sync();
}, 1000);
}
const task2 = () => {
setTimeout(() => {
console.log(4);
sync();
}, 2000);
}
console.log(1);
task1();
task2();
console.log(2);

Promises

Promises can be composed together more easily.

const task1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(3);
resolve();
}, 1000);
});
}
const task2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(4);
resolve();
}, 2000);
});
}

Series

console.log(1);
task1()
.then(() => {
return task2();
});
console.log(2)
(async () => {
console.log(1);
console.log(2);
await task1();
await task2();
})();

Parallel

const sync = () => {
console.log(5);
}
console.log(1);
Promise.all([task1(), task2()])
.then(() => {
sync();
});
console.log(2);
(async () => {
console.log(1);
console.log(2);
await Promise.all([task1(), task2()]);
sync();
})()

Errors

const task = () => {
return new Promise((resolve, reject) => {
reject(new Error('oh no!'));
});
};
task().catch(err => {
console.error(err);
});
(async function() {
try {
await task();
} catch(err) {
console.error(err);
}
})();

tsukiy0