These ten questions run the length of the chapter, and every one of them turns on behavior that catches working Node developers out. Treat each numbered snippet as a separate file, run nothing, and write down exactly what it prints and why. The answers, with the reasoning and the section each comes from, are in Appendix G.
Questions
// 1. m.mjs holds `export const answer = 42;` and `export default 'D';`
// m.cjs holds `module.exports = { answer: 42 };`. Why is there no ERR_REQUIRE_ESM?
const m = require('./m.mjs');
const c = require('./m.cjs');
console.log(typeof m, m.answer, m.default, m.__esModule);
console.log(Object.keys(m).join(), m[Symbol.toStringTag]);
console.log(c.answer, c.default, m === require('./m.mjs'));
// 2. node:path does string surgery, never disk access. Which line is a security hole?
import path from 'node:path';
const p = path.posix;
console.log(p.join('/uploads', '../../etc/passwd'));
console.log(p.resolve('/srv', '/etc', 'passwd'), JSON.stringify(p.extname('.env')));
console.log(p.normalize('a//b/./c/'), JSON.stringify(p.parse('/x/y.tar.gz').ext));
// 3. One character, cut in half. Both numbers and all three strings matter.
const d = new TextDecoder(), s = new TextDecoder();
const b = Buffer.from('\u20AC10'); // a euro sign followed by "10"
console.log(b.length, '\u20AC10'.length);
console.log(d.decode(b.subarray(0, 2)) + d.decode(b.subarray(2)));
console.log(s.decode(b.subarray(0, 2), { stream: true }) + s.decode(b.subarray(2)));
console.log(b.toString('latin1').length, b.toString('base64'));// 4. A writable that buffers 4 bytes and takes 20 ms per chunk. Does 'drain' ever fire?
import { Writable } from 'node:stream';
const w = new Writable({ highWaterMark: 4, write(c, enc, cb) { setTimeout(cb, 20); } });
w.on('drain', () => console.log('drain', w.writableLength));
console.log(w.write('ab'), w.write('cd'), w.write('ef'));
console.log(w.writableLength, w.writableNeedDrain, w.writableHighWaterMark);
w.end(() => console.log('finished', w.writableFinished, w.writableLength));
// 5. Nothing ever emits 'go' or 'ready'. Only one of the two waits reports a failure.
import { EventEmitter, once } from 'node:events';
const em = new EventEmitter();
const ac = new AbortController();
setTimeout(() => ac.abort(), 20);
await once(em, 'go', { signal: ac.signal }).catch((e) => console.log('caught', e.name));
console.log('waiting');
await once(em, 'ready', { signal: AbortSignal.timeout(50) });
console.log('done'); // what is the exit code of this process?
// 6. Four details here are not what a first reading suggests.
const u = new URL('/search?q=a+b&tag=x&tag=y#top', 'https://example.com:443/ignored');
console.log(u.href);
console.log(u.searchParams.get('q'), u.searchParams.getAll('tag'), JSON.stringify(u.port));
console.log(new URL('../b?x=1', 'https://example.com/a/c/d').href);
console.log(String(new URLSearchParams({ q: 'a b', n: 1 })));// 7. Why does the first value end in 1, and why is the last one not Object.prototype?
import { parseArgs } from 'node:util';
const { values, positionals } = parseArgs({
args: ['--port', '8080', 'serve'],
options: { port: { type: 'string' } }, allowPositionals: true });
console.log(values.port + 1, positionals, values.toString, Object.getPrototypeOf(values));
const r = parseArgs({ args: ['-vv', '--tag=a', '--tag=b'], options: {
v: { type: 'boolean', short: 'v', multiple: true },
tag: { type: 'string', multiple: true } } });
console.log(r.values.v, r.values.tag);
// 8. Four workers, one shared counter, 200,000 increments each. What is the total,
// and which one-line change makes it exact every time?
import { Worker } from 'node:worker_threads';
const counter = new Int32Array(new SharedArrayBuffer(4));
const src = "const c=require('node:worker_threads').workerData;for(let i=0;i<2e5;i++)c[0]++;";
await Promise.all([1, 2, 3, 4].map(() => new Promise((res) =>
new Worker(src, { eval: true, workerData: counter }).on('exit', res))));
console.log(counter[0], counter[0] === 800000);// 9. Three of these seven pass. Which three, and what single rule explains the first line?
import assert from 'node:assert/strict';
const t = (f) => { try { f(); return 'passes'; } catch { return 'throws'; } };
console.log(t(() => assert.strictEqual(NaN, NaN)), t(() => assert.strictEqual(0, -0)));
console.log(t(() => assert.deepStrictEqual({ a: 1, b: 2 }, { a: 1 })),
t(() => assert.partialDeepStrictEqual({ a: 1, b: 2 }, { a: 1 })));
console.log(t(() => assert.deepStrictEqual([1, 2], new Set([1, 2]))),
t(() => assert.deepStrictEqual({ a: 1 }, { a: '1' })), t(() => assert(' ')));
// 10. Run as: node --permission --allow-fs-read="C:\app\*" report.mjs
// data.txt sits in C:\app, and nothing else was granted. Why is the first false?
import { readFileSync } from 'node:fs';
const perm = process.permission;
console.log(perm.has('fs.read'), perm.has('fs.read', './data.txt'));
console.log(perm.has('fs.write', './data.txt'), perm.has('child'));
try { readFileSync('C:/Windows/win.ini'); } catch (e) { console.log(e.code, e.permission); }