Blocking Promises Examples

Promises do not magically unblock the event loop. To fight it use setTimeout, Worker, and other actually non-blocking APIs.

Off the main thread! (good podcast btw)

Some examples which block or dont block the event loop

❌ blocks event loop

export function wait() {
  let start = Date.now()
  while (Date.now() - start < 5000) {}
  // good old sync function
  // event loop is frozen until 5s has passed
  return true
}

❌ blocks event loop

export function wait() {
  return new Promise((resolve) => {
    let start = Date.now()
    while (Date.now() - start < 5000) {}
    // wrapping in a promise wont help
    // the work is still done in main thread
    resolve(true)
  })
}

❌ blocks event loop

function hardSyncWork() {
  return new Promise((resolve) => {
    let start = Date.now()
    while (Date.now() - start < 5000) {}
    resolve(true)
  })
}

export function wait() {
  return new Promise((resolve) => hardSyncWork().then(resolve))
  // No matter how many promises there are,
  // the work will stay blocking
}

✅ does not block event loop

export function wait() {
  return new Promise((resolve) => {
    setTimeout(() => resolve(true), 5000)
    // first non blocking fn!
    // setTimeout is non blocking, it pushes tasks to macrotask queue
  })
}

✅ does not block event loop

import { Worker, isMainThread, parentPort } from 'node:worker_threads'
import { fileURLToPath } from 'url'

const __filename = fileURLToPath(import.meta.url)

export let wait = null
// Crazy way to convert actually blocking work to non blockin :ooo

if (isMainThread) {
  wait = function () {
    return new Promise((resolve) =>
      new Worker(__filename).on('message', resolve)
    )
  }
} else {
  let start = Date.now()
  while (Date.now() - start < 5000) {}
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // non blocking real work as its executed in a worker
  // (off the main thread)
  parentPort.postMessage(true)
}

❌ blocks event loop

import fs from 'node:fs'

export function read() {
  fs.writeFileSync('temp.txt', 'long string')
  // writeFileSync blocks by design.
  return true
}

❌ blocks event loop

import fs from 'node:fs'

export function read() {
  return new Promise((resolve) => {
    fs.writeFileSync('temp.txt', 'long string')
    // running writeFileSync in a promise does not help.
    // the function is blocking by design.
    resolve(true)
  })
}

✅ does not block event loop

import fs from 'node:fs'

export function read() {
  return new Promise((resolve) => {
    fs.writeFile('temp.txt', 'long string', {}, () => resolve(true))
    // Promises are really just syntactic sugar.
    // Conceptually callback functions + pushed to microtask queue
    // This is non blocking :)
  })
}

✅ does not block event loop

import fs from 'node:fs/promises'

export function read() {
  return fs.writeFile('temp.txt', 'long string')
  // fs/promises functions are non blocking
  // but this is not because of promises.
  // its because it uses nonblocking C-lang bound functions internally
}

Bye!