📘 JavaScript Advanced Interview Notes
Deep Async, Event Loop, Tricky Outputs & Machine Coding
Table of Contents
Part 1: Deep Async JavaScript & Event Loop
- JavaScript Is Single-Threaded — Then How Is Async Possible?
- Runtime Architecture
- Event Loop Priority Order
- Microtasks vs Macrotasks
- Deep Event Loop Example
- Nested Microtasks
- async / await Internals
- await vs then
- Blocking the Event Loop
Part 2: Output-Based Tricky JavaScript Questions
- var + Closure
- let vs var Hoisting
- this Confusion
- Arrow Function this Trap
- Object Mutation
- Object Keys Stringification
- == Weirdness
- Function Hoisting Priority
Part 3: JavaScript Machine Coding Questions
- Debounce Function
- Throttle Function
- Polyfill for Promise.all
- Polyfill for bind
- Flatten Nested Array
- Deep Clone Object
- Once Function
- Implement Event Emitter
- Retry Promise Function
- Implement sleep
1. Deep Async JavaScript & Event Loop (INTERNALS)
1.1 JavaScript Is Single-Threaded — Then How Is Async Possible?
JavaScript has:
- Single Call Stack
- Asynchronous runtime environment
Async behavior is handled by:
- Web APIs
- Task queues
- Event Loop
1.2 Runtime Architecture (Mental Diagram)
┌──────────────┐
│ Call Stack │
└──────┬───────┘
│
┌──────▼───────┐
│ Web APIs │ (setTimeout, fetch, DOM events)
└──────┬───────┘
│
┌──────▼──────────┐
│ Task Queues │
│ - Microtasks │ (Promises, queueMicrotask)
│ - Macrotasks │ (setTimeout, setInterval)
└──────┬──────────┘
│
┌──────▼───────┐
│ Event Loop │
└──────────────┘
1.3 Event Loop Priority Order (CRITICAL)
Execution order:
- Call Stack
- Microtask Queue
- Macrotask Queue
Microtasks always execute before macrotasks
1.4 Microtasks vs Macrotasks
Microtasks
- Promise.then
- Promise.catch
- Promise.finally
- queueMicrotask
- MutationObserver
Macrotasks
- setTimeout
- setInterval
- setImmediate (Node)
- requestAnimationFrame
1.5 Deep Event Loop Example (Most Asked)
console.log("A");
setTimeout(() => {
console.log("B");
}, 0);
Promise.resolve().then(() => {
console.log("C");
});
console.log("D");
Execution Breakdown
A→ Call stacksetTimeout→ Web APIPromise.then→ Microtask queueD→ Call stack empty- Microtask →
C - Macrotask →
B
Output
A
D
C
B
1.6 Nested Microtasks (Very Tricky)
Promise.resolve().then(() => {
console.log("A");
Promise.resolve().then(() => {
console.log("B");
});
});
setTimeout(() => {
console.log("C");
}, 0);
Output
A
B
C
Reason:
- Microtasks can schedule more microtasks
- All microtasks must finish before macrotasks
1.7 async / await Internals (IMPORTANT)
async function test() {
console.log("A");
await Promise.resolve();
console.log("B");
}
console.log("C");
test();
console.log("D");
How it works internally
awaitpauses function execution- Remaining code goes to microtask queue
Output
C
A
D
B
1.8 await vs then (Same Priority)
await Promise.resolve();
Promise.resolve().then();
Both go to microtask queue.
1.9 Blocking the Event Loop (Interview Trap)
setTimeout(() => console.log("A"), 0);
for (let i = 0; i < 1e10; i++) {}
console.log("B");
Output
B
A
Why:
- Call stack is blocked
- Event loop cannot push tasks
2. Output-Based Tricky JavaScript Questions
2.1 var + Closure (Classic)
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
Output
3
3
3
Fix
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
2.2 let vs var Hoisting
console.log(a);
var a = 10;
console.log(b);
let b = 20;
Output
undefined
ReferenceError
2.3 this Confusion
const obj = {
name: "JS",
getName: function () {
return this.name;
},
};
const fn = obj.getName;
console.log(fn());
Output
undefined
Reason:
- Lost context
this→ global / undefined (strict)
2.4 Arrow Function this Trap
const obj = {
name: "JS",
greet: () => {
console.log(this.name);
},
};
obj.greet();
Output
undefined
Arrow functions do not bind this
2.5 Object Mutation
const obj = { a: 1 };
const obj2 = obj;
obj2.a = 2;
console.log(obj.a);
Output
2
2.6 Object Keys Stringification
const obj = {};
obj[1] = "one";
obj["1"] = "one again";
console.log(obj);
Output
{ "1": "one again" }
2.7 == Weirdness
[] == ![];
Output
true
Explanation:
![]→ false[] == false→"" == 0→ true
2.8 Function Hoisting Priority
foo();
var foo = function () {
console.log("A");
};
function foo() {
console.log("B");
}
Output
B
Function declarations beat var
3. JavaScript Machine Coding Questions (INTERVIEW LEVEL)
3.1 Debounce Function
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
Use cases:
- Search input
- Resize events
3.2 Throttle Function
function throttle(fn, limit) {
let lastCall = 0;
return function (...args) {
const now = Date.now();
if (now - lastCall >= limit) {
lastCall = now;
fn.apply(this, args);
}
};
}
Use cases:
- Scroll events
- Infinite scroll
3.3 Polyfill for Promise.all
Promise.myAll = function (promises) {
return new Promise((resolve, reject) => {
const results = [];
let completed = 0;
promises.forEach((p, i) => {
Promise.resolve(p)
.then((res) => {
results[i] = res;
completed++;
if (completed === promises.length) {
resolve(results);
}
})
.catch(reject);
});
});
};
3.4 Polyfill for bind
Function.prototype.myBind = function (context, ...args) {
const fn = this;
return function (...innerArgs) {
return fn.apply(context, [...args, ...innerArgs]);
};
};
3.5 Flatten Nested Array
function flatten(arr) {
return arr.reduce((acc, val) => {
if (Array.isArray(val)) {
acc.push(...flatten(val));
} else {
acc.push(val);
}
return acc;
}, []);
}
3.6 Deep Clone Object
function deepClone(obj) {
if (obj === null || typeof obj !== "object") return obj;
const copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
copy[key] = deepClone(obj[key]);
}
return copy;
}
3.7 Once Function
function once(fn) {
let called = false;
let result;
return function (...args) {
if (!called) {
called = true;
result = fn.apply(this, args);
}
return result;
};
}
3.8 Implement Event Emitter
class EventEmitter {
constructor() {
this.events = {};
}
on(event, fn) {
this.events[event] = this.events[event] || [];
this.events[event].push(fn);
}
emit(event, data) {
(this.events[event] || []).forEach((fn) => fn(data));
}
off(event, fn) {
this.events[event] = (this.events[event] || []).filter((f) => f !== fn);
}
}
3.9 Retry Promise Function
function retry(fn, retries) {
return fn().catch((err) => {
if (retries === 0) throw err;
return retry(fn, retries - 1);
});
}
3.10 Implement sleep
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}