askesis

Advanced JavaScript flashcards: event loop, generators and more

Fifty advanced JavaScript cards: event-loop ordering puzzles, generators and async iteration, this binding, Proxy and Reflect, modules, AbortController and coercion edge cases.

ProgrammingIntermediate50 cardsFree

Practice now

Study without an account

0 of 50 seen0 graduated
In what order does this log?
js
console.log(1)
setTimeout(() => console.log(2))
queueMicrotask(() => console.log(3))
Promise.resolve().then(() => console.log(4))
console.log(5)

Scheduled with the default Askesis timings. Progress is saved in this browser.

All 50 cards

  1. 1
    In what order does this log?
    js
    console.log(1)
    setTimeout(() => console.log(2))
    queueMicrotask(() => console.log(3))
    Promise.resolve().then(() => console.log(4))
    console.log(5)
    1 5 3 4 2: synchronous code, then microtasks in the order they were queued, then the timer
  2. 2
    In what order does this log?
    js
    async function f() {
      console.log('a')
      await null
      console.log('b')
    }
    f()
    console.log('c')
    a c b: everything after await runs later as a microtask
  3. 3
    In what order does this log?
    js
    Promise.resolve().then(() => {
      console.log('m1')
      setTimeout(() => console.log('t2'))
    })
    setTimeout(() => {
      console.log('t1')
      Promise.resolve().then(() => console.log('m2'))
    })
    m1 t1 m2 t2: after each task (like a timer callback) the microtask queue is drained before the next task
  4. 4
    Can microtasks starve the page?
    Yes. Microtasks queued by microtasks all run before rendering or the next timer, so an endless chain freezes the page
  5. 5
    When does a requestAnimationFrame callback run?
    Before the browser’s next repaint, usually about 60 times a second; it’s paused in background tabs
  6. 6
    What does Promise.withResolvers() return?
    { promise, resolve, reject }, so you can settle a promise from outside its executor (ES2024)
  7. 7
    What happens to a rejected promise nobody handles?
    Browsers fire an unhandledrejection event; Node.js crashes the process by default (since Node 15)
  8. 8
    Sequential vs concurrent awaits
    js
    // one after another
    for (const url of urls) await fetch(url)
    
    // all at once
    await Promise.all(urls.map((url) => fetch(url)))
  9. 9
    Why write return await inside try?
    Without await, a rejection happens after the function returns, so the surrounding catch never sees it
    js
    try {
      return await risky()
    } catch (err) {
      return fallback
    }
  10. 10
    What does for await...of iterate?
    Async iterables (and sync iterables of promises), awaiting each value in turn
  11. 11
    What is an async generator?
    An async function* that can await and yield; consume it with for await
    js
    async function* pages(url) {
      while (url) {
        const res = await (await fetch(url)).json()
        yield res.items
        url = res.next
      }
    }
  12. 12
    What does calling a generator function return?
    An iterator; the body runs only when you call next(), pausing at each yield
    js
    function* ids() {
      let i = 0
      while (true) yield i++
    }
    const it = ids()
    it.next().value // 0
  13. 13
    What does an iterator’s next() return?
    { value, done }; done is true once the iterator is exhausted
  14. 14
    Make an object iterable
    Give it a [Symbol.iterator] method that returns an iterator (a generator is easiest)
    js
    const range = {
      from: 1,
      to: 3,
      *[Symbol.iterator]() {
        for (let i = this.from; i <= this.to; i++) yield i
      },
    }
    [...range] // [1, 2, 3]
  15. 15
    What does Symbol.asyncIterator enable?
    Using an object with for await...of
  16. 16
    What does Symbol.toPrimitive customize?
    How an object converts to a primitive; it receives a hint: "number", "string" or "default"
  17. 17
    What does Object.create(null) give you?
    An object with no prototype: no inherited keys like toString, handy as a plain dictionary
  18. 18
    Class method vs arrow-function class field
    Methods live once on the prototype; arrow fields are created per instance and keep this bound
    js
    class Button {
      click() {}          // shared, on the prototype
      onClick = () => {}  // per instance, `this` fixed
    }
  19. 19
    Where do static class members live?
    On the class (constructor) itself, not on instances
  20. 20
    In a subclass constructor, what must happen before you use this?
    A call to super(...); using this first throws a ReferenceError
  21. 21
    Precedence of the this binding rules
    new › explicit (call/apply/bind) › method call (obj.fn()) › default (undefined in strict mode)
  22. 22
    Why is this undefined here? const f = obj.method; f()
    The method was called without its object; bind it (obj.method.bind(obj)) or wrap it in an arrow
    In strict mode (modules, classes) it’s undefined; in sloppy scripts it’s the global object.
  23. 23
    Can you change this by calling bind on a bound function?
    No. The first bind wins; later bind calls can only add arguments
  24. 24
    Break out of a nested loop
    Label the outer loop and break to the label
    js
    outer: for (const row of grid) {
      for (const cell of row) {
        if (cell === target) break outer
      }
    }
  25. 25
    What does this log?
    js
    for (var i = 0; i < 3; i++) {
      setTimeout(() => console.log(i))
    }
    3 3 3: one shared var. With let, each iteration gets its own binding and it logs 0 1 2
  26. 26
    How do closures cause memory leaks?
    A closure keeps everything it captures alive while the function is reachable, so long-lived listeners and timers can pin large objects
  27. 27
    What does WeakRef do?
    Holds an object without keeping it alive; ref.deref() returns it, or undefined once it’s collected
  28. 28
    What is FinalizationRegistry for?
    Running a callback some time after a registered object is garbage-collected; timing isn’t guaranteed
  29. 29
    A typical use of WeakSet
    Marking objects (like “already processed”) without stopping them from being garbage-collected
  30. 30
    What is a Proxy?
    A wrapper that intercepts operations on an object through traps like get, set and has
    js
    const logged = new Proxy(target, {
      get(t, key, receiver) {
        console.log('read', key)
        return Reflect.get(t, key, receiver)
      },
    })
  31. 31
    Why use Reflect inside proxy traps?
    Reflect.get, Reflect.set and friends perform the default operation, so a trap can add behavior and then forward
  32. 32
    Define a getter and a setter
    js
    const user = {
      first: 'Ada', last: 'Lovelace',
      get full() { return `${this.first} ${this.last}` },
      set full(v) { [this.first, this.last] = v.split(' ') },
    }
  33. 33
    Defaults of writable, enumerable and configurable with Object.defineProperty
    All false unless you set them
  34. 34
    Is Object.freeze deep?
    No, it’s shallow: nested objects stay mutable. Writes to a frozen property fail silently, or throw in strict mode
  35. 35
    What can’t structuredClone copy?
    Functions and DOM nodes (it throws), and it drops prototypes, so class instances come back as plain objects
  36. 36
    ES modules vs CommonJS
    ESM import/export is static, loaded asynchronously and always strict; CommonJS require runs synchronously at call time
  37. 37
    What is a live binding?
    An ES module import that reflects later changes to the exported variable; CommonJS copies the value when you require it
  38. 38
    Load a module on demand
    js
    const { render } = await import('./chart.js')
    Dynamic import() returns a promise and enables code splitting.
  39. 39
    Where is top-level await allowed?
    In ES modules. Modules that import one wait for it to finish evaluating
  40. 40
    Throttle
    Run a function at most once per interval
    js
    function throttle(fn, ms) {
      let last = 0
      return (...args) => {
        const now = Date.now()
        if (now - last >= ms) {
          last = now
          fn(...args)
        }
      }
    }
  41. 41
    Cancel a fetch
    js
    const ctrl = new AbortController()
    fetch(url, { signal: ctrl.signal })
    ctrl.abort() // the fetch rejects with an AbortError
  42. 42
    Give a fetch a timeout
    js
    fetch(url, { signal: AbortSignal.timeout(5000) })
    It rejects with a TimeoutError after 5 seconds.
  43. 43
    Uint8Array vs Uint8ClampedArray
    Both store bytes; out-of-range values wrap around in Uint8Array (256 → 0) and clamp to 0–255 in the clamped one
  44. 44
    What does a template tag function receive?
    The literal string parts, then the interpolated values
    js
    function upper(strings, ...values) {
      return strings.reduce((out, s, i) => out + s + (values[i]?.toUpperCase() ?? ''), '')
    }
    upper`hi ${'ada'}!` // 'hi ADA!'
  45. 45
    Object.is(-0, 0) and Object.is(NaN, NaN)
    false and true, the opposite of ===
  46. 46
    [] + {} and [] + []
    '[object Object]' and '': both sides convert to strings, then concatenate
  47. 47
    '5' - 2 vs '5' + 2
    3 vs '52': - converts to numbers, + concatenates when either side is a string
  48. 48
    0.1 + 0.2 === 0.3
    false; floating-point rounding gives 0.30000000000000004
    Compare with a tolerance: Math.abs(a - b) < Number.EPSILON.
  49. 49
    Group array items by a key
    js
    Object.groupBy(cards, (c) => c.deck) // { Japanese: [...], Spanish: [...] }
    ES2024. Map.groupBy does the same into a Map.
  50. 50
    sort vs toSorted
    sort reorders the array in place; toSorted returns a sorted copy (ES2023)

Frequently asked questions

Should I start with this deck?

Start with JavaScript essentials. This deck assumes you know closures, promises and array methods.

Are the event-loop answers the same in Node.js?

Yes for these examples: microtasks run before the next timer callback in both browsers and Node.js.

Is it useful for senior interviews?

Yes. Event-loop ordering, this binding and generators are classic senior-level questions.

Intermediate

JavaScript

Master the JavaScript every developer uses daily: scope, closures, equality, array methods, promises, async/await and the event loop.

50 cards
Intermediate

TypeScript

Learn the TypeScript you use every day: narrowing, generics, keyof, mapped and conditional types, utility types, satisfies and strict mode, with code on every card.

50 cards
Beginner

Python

Learn idiomatic Python fast: comprehensions, f-strings, args and kwargs, generators, decorators, context managers and the standard library.

50 cards
Beginner

Git & terminal

The Git commands and shell skills developers use every day: branching, rebasing, undoing mistakes, pipes, redirects, permissions and processes.

50 cards
Beginner

Java

Core Java with short snippets: equals vs ==, records, sealed types, collections, generics, exceptions, streams, lambdas and JVM basics.

50 cards
Beginner

C#

C# and .NET fundamentals with short snippets: value vs reference types, properties, records, nullable reference types, LINQ, async/await and DI.

50 cards
Beginner

Kotlin

Kotlin fundamentals with short snippets: null safety, val vs var, data and sealed classes, extension functions, scope functions and coroutines.

50 cards
Beginner

Swift

Swift fundamentals with short snippets: optionals, structs vs classes, protocols, enums with associated values, closures, ARC, async/await and SwiftUI.

50 cards
Beginner

Flutter

Flutter and Dart basics: null safety, futures and streams, stateless vs stateful widgets, setState, hot reload, keys, layout and state management.

50 cards
Beginner

PHP

Modern PHP 8 with short snippets: strict types, arrays, match, nullsafe and named arguments, enums, readonly, Composer, PDO and password_hash.

50 cards
Beginner

Ruby

Ruby fundamentals with short snippets: blocks, procs and lambdas, symbols, Enumerable, mixins, truthiness, method_missing, gems and Bundler.

50 cards
Beginner

Go

Go (Golang) fundamentals with short, idiomatic snippets: slices vs arrays, maps, defer, error wrapping, interfaces, goroutines, channels, select and context.

50 cards
Intermediate

Rust

Learn the Rust that the compiler keeps asking about: ownership, borrowing, lifetimes, Option and Result, traits, closures, smart pointers and async.

50 cards
Intermediate

C++

Modern C++ in short snippets: references vs pointers, RAII, smart pointers, move semantics, STL containers and algorithms, const, templates and UB.

50 cards
Intermediate

Haskell

Haskell fundamentals with short code: types and type classes, pattern matching, laziness, Maybe and Either, folds, Functor, Applicative and Monad.

50 cards
Intermediate

Elixir

Elixir fundamentals with short snippets: immutability, pattern matching, the pipe operator, Enum vs Stream, processes, GenServer, supervisors and mix.

50 cards
Intermediate

x86-64 assembly

x86-64 assembly in Intel syntax: registers and sub-registers, flags, mov and lea, jumps, the stack frame, the System V calling convention and Linux syscalls.

50 cards
Beginner

Regex

Learn regular expressions for good: anchors, classes, greedy vs lazy quantifiers, groups, lookarounds, flags, replacements and the backtracking trap.

50 cards