- Which statement best compares the likely behavior?
Answer: Synchronous work can delay the timer in both environments, and in the browser it can additionally delay pending page rendering.
When you see a question comparing JavaScript behavior across environments, your anchor concept should be the event loop — and critically, how synchronous code interacts with it in every JavaScript runtime.
Here's the core principle: JavaScript is single-threaded. Whether in a browser or Node.js, the event loop cannot process any queued callbacks — including timer callbacks — while synchronous code is still executing on the call stack. A setTimeout(..., 0) doesn't mean "run immediately"; it means "queue this callback as soon as possible, but only after the current synchronous task finishes." That makes B correct: heavy synchronous computation blocks the timer callback in both environments. The browser adds an extra layer — it also uses the event loop to schedule visual rendering (via the rendering pipeline). Blocked JavaScript means the browser can't repaint or respond to user input either, making the page appear frozen during the computation.
A is wrong because it invents a "browser security" rule. No such mechanism exists — both environments block timers the same way, for the same architectural reason (single-threaded event loop), not for security.
C is doubly wrong. The browser does not render during synchronous computation — that's exactly the problem with long-running JS. And Node.js absolutely has an event loop; it's foundational to how Node handles I/O.
D is wrong because zero-delay doesn't grant priority over currently-executing synchronous code. The callback still waits for the call stack to clear before it can run.
A useful mental model: think of the call stack as a locked door — the event loop can only deliver new tasks (timers, renders, I/O) once that door opens.
- Which assessment is most accurate?
Answer: The package may require a browser-specific implementation or server-side use because ordinary browser code cannot perform that Node.js file-system operation.
When you see a question mixing npm packages with browser environments, the core concept to test is runtime compatibility — npm is a distribution tool, not a compatibility layer. The JavaScript ecosystem has two major runtimes: browsers and Node.js. They share the language itself (via engines like V8), but each exposes different host APIs on top of it.
Node.js provides APIs like node:fs specifically because it runs on a server with access to the operating system's file system. Browsers, by design, have no such access — a webpage cannot freely read files from your hard drive, as that would be a serious security vulnerability. No amount of bundling or npm installation changes this fundamental boundary. That's why C is correct: the package needs either a browser-specific reimplementation (perhaps using the File System Access API with user permission) or must remain server-side.
A is wrong because npm does nothing to transform code — it simply fetches and installs packages. Compatibility is entirely the developer's responsibility. B contains a subtle but important misconception: V8 is just the JavaScript engine (it parses and executes JS syntax), but fs is a Node.js host API layered on top. Sharing the engine does not mean sharing host APIs — browsers also use V8 but do not expose fs. D is wrong because node:fs and fs refer to the same Node.js built-in module; the node: prefix is just an explicit namespace convention. Dropping it changes nothing about browser incompatibility.
As a general study tip: always distinguish between the JavaScript engine, the runtime environment, and the host APIs — they are three separate layers that questions often deliberately conflate.
- What does the use of
globalThis establish about the library? Answer: It gives the library a standard way to reference the current global object, but it does not guarantee that browser-specific properties exist in Node.js.
When you see a question about globalThis, ask yourself: what problem does it solve, and what does it promise? globalThis was introduced to give JavaScript developers a single, consistent way to reference the global object regardless of environment — window in browsers, global in Node.js, self in Web Workers. That's its entire purpose: a universal handle, not a magic compatibility layer.
That's exactly why A is correct. When the library uses globalThis.libraryState = {}, it's writing to the global scope in a way that works across environments. When it checks globalThis.document, it's carefully asking whether a browser API exists before using it — a smart cross-environment pattern. But globalThis itself only provides the reference; it doesn't conjure browser APIs out of thin air in Node.js. document simply won't be there unless something explicitly provides it.
B describes something that doesn't exist. There are no "automatic runtime polyfills" that bridge browser APIs into Node.js — that would require explicit tools like jsdom. C has the runtime backwards: browsers have historically used window as the global name, not Node.js. Node.js uses global. Neither environment restricts globalThis — it works in both. D is the opposite of how globalThis behaves. It explicitly exposes properties on the shared global scope, meaning any code in the same runtime can access libraryState. Module-level isolation would mean declaring const libraryState = {} without attaching it to globalThis at all.
A useful mental shortcut: globalThis = universal pointer, not universal compatibility. It points to the right global object everywhere, but what lives on that object still depends on the runtime.
- What is the best interpretation of this result?
Answer: The check is unreliable because an API can exist in multiple runtimes; the library should test the capability it actually needs.
When a library uses typeof fetch === "function" to detect its environment, it's making a classic duck-typing mistake — assuming that because one API exists, an entire ecosystem of behavior must follow. The key concept here is that runtime environments are not monolithic: individual APIs can be ported across runtimes without bringing everything else along with them.
Node.js 18+ added a native fetch implementation to its global scope, which means the check returns true in both a modern browser and Node.js 20. This doesn't mean the environments are equivalent — it just means one specific API landed in both places. A library that uses this check to decide, say, whether window, document, or browser-specific security policies are available will break in Node.js, because none of those exist there. D is correct: the check is unreliable because API presence doesn't guarantee behavioral equivalence, and the library should instead test the specific capability it actually requires (e.g., typeof document !== "undefined" for DOM needs).
A is wrong because Node.js doesn't "emulate" a browser environment — it intentionally adopted fetch as a standalone networking API, not as part of any compatibility layer. B is wrong because the JavaScript runtime executing the file is determined by how you launch it (node vs. browser tab), not by what APIs happen to be available. C is wrong because having one matching API says nothing about global object parity — Node.js has no DOM, no window, no localStorage, and so on.
Your strategy takeaway: when you see environment detection code, always ask "what assumption is this check actually making?" Presence of one feature never guarantees the presence of everything that feature implies.
- Which conclusion is most important when adapting this code for the browser?
Answer: Public configuration may be embedded, but a secret embedded in the delivered bundle can be inspected by browser users.
When you see a question about bundling Node.js code for the browser, the core issue to focus on is where code actually executes and who can see it. Node.js environment variables live on a server — users never access them directly. But a browser bundle is a file delivered to and readable by anyone who opens DevTools.
Build tools like Webpack or Vite can replace process.env.API_URL with its literal string value at bundle time. This is useful for things like a public API endpoint — embedding "https://api.example.com" is harmless. The critical insight behind answer C is that the same substitution applied to a secret key doesn't protect it. Once process.env.SECRET_KEY is replaced with "abc123secret", that string is sitting in plain JavaScript that any user can read by opening the browser's source viewer or network tab. Bundling doesn't encrypt or hide values — it just inlines them.
Answer A is wrong because browser bundles have no concept of Node.js access controls. Once a value is inlined, it's just a string literal with zero access restrictions. Answer B invents a fictional browser-side process.env security model — no such per-module privacy mechanism exists in browsers. Answer D is simply false; build tools routinely handle process references and successfully produce valid browser bundles from such code.
A good rule of thumb: anything embedded in a browser bundle should be treated as public. If a value must stay secret, it belongs on the server — accessed via an API call, never inlined into client-side code.
- Which outcome best explains why the file is not portable between the two environments?
Answer: The browser throws on process (unavailable there) while Node.js throws on document (unavailable there), because each runtime lacks the other's host API.
When working with JavaScript portability questions, think about the fundamental split between the language itself (ECMAScript) and the runtime environment that hosts it. JavaScript the language doesn't include document or process — those are host-provided globals injected by the browser and Node.js, respectively.
This is exactly why B is correct. When the browser executes the file, it has document.title available, but process is simply not defined — accessing it throws a ReferenceError. Flip the environment: Node.js has process.platform, but document is undefined, causing its own ReferenceError. Neither execution completes successfully, and the root cause is that each runtime only exposes its own host APIs, not the other's.
A is wrong because this is not a syntax issue. Both document and process are perfectly valid JavaScript identifiers — the parser accepts them without complaint. The problem is a runtime reference error, not a parsing failure.
C describes a behavior that doesn't exist. JavaScript does not silently coerce undefined global references to empty strings. Accessing a variable that was never declared throws a ReferenceError — it doesn't return "" or undefined quietly. If the globals were properties of an object that existed, you'd get undefined, but top-level undeclared variables are a harder error.
D is pure fiction. JavaScript has no automatic mapping between environments. The language spec defines no equivalence between browser and Node.js host objects.
Your study tip: always separate ECMAScript (the language standard) from host environment APIs. On exam questions about cross-environment compatibility, the trap is assuming one runtime's globals exist in another.
- Why can the two relative strings refer to different resources?
Answer: Browser relative URLs resolve from the page's base URL, while Node.js relative paths resolve from the process working directory.
When you see a question mixing browser fetch() and Node.js file system calls, focus on where each environment anchors relative paths — that's the core distinction being tested.
In a browser, relative URLs are resolved against the page's base URL. So when https://example.test/app/index.html calls fetch("./config.json"), the browser resolves it as https://example.test/app/config.json — starting from the directory containing the HTML file. In Node.js, however, relative paths passed to file system methods like readFileSync are resolved against the process's current working directory (CWD), not the script file's location. Since the CWD is /srv/app/, Node looks for /srv/app/config.json, even though the script itself lives in /srv/app/scripts/. Same string, different resources — which is exactly what A describes.
B is wrong on both counts: browsers don't use the user's home directory, and Node.js doesn't resolve from the source file's location by default (that would require __dirname). C is wrong because the two environments don't share the same resolution base, and Node.js has no built-in behavior that strips a directory segment from CommonJS paths. D is fabricated — there's no concept of a shared web origin between a browser and Node.js, and CORS has nothing to do with local file path resolution.
A useful tip: remember that in Node.js, __dirname gives you the script's directory, while process.cwd() gives the working directory — these are often different, and confusing them is a common source of bugs.
- Which redesign most accurately reflects the browser's execution model?
Answer: Use the browser's File APIs after the user selects or grants access to a file, rather than assuming unrestricted path access.
When you see a question comparing Node.js capabilities to browser JavaScript, the key concept to focus on is the security sandbox that browsers enforce. Unlike Node.js, which runs with the operating system's file permissions and can freely access the filesystem, browsers deliberately isolate JavaScript from the user's local files to prevent malicious websites from reading arbitrary data off your machine.
This is exactly why A is correct. The browser's execution model requires explicit user consent before any file can be accessed. APIs like <input type="file">, the FileReader API, or the newer File System Access API all require the user to actively select or grant access to a file. The browser never allows a script to say "give me /reports/annual.txt" and just receive it — the user must be the one to initiate that trust relationship.
B describes a fundamental misunderstanding of fetch. While fetch can request files via the file:// protocol in limited local contexts, it absolutely cannot grant a page unrestricted access to any local path by name — that would be a catastrophic security vulnerability.
C is nonsense by design. node:fs is a Node.js core module that interacts with the OS kernel directly. Importing it from a CDN doesn't transfer anything — Node.js APIs simply don't exist in the browser runtime, regardless of where you load the code from.
D is similarly fictional. Setting a string on window has no relationship to the filesystem whatsoever; the browser doesn't monitor property assignments for path-like strings.
Your study tip: whenever a question contrasts Node.js with browser JS, ask yourself who controls access — in browsers, it's always the user, never the script.
- Why can the browser fail even though both environments support ES module syntax?
Answer: Node.js can resolve the bare package specifier using its package rules, while the browser needs a mapped or URL-like module specifier.
When working with ES modules across environments, the critical concept is module specifier resolution — how the runtime figures out where to find the file you're importing.
Node.js has a well-defined algorithm for resolving bare specifiers like "data-tools". It walks up the directory tree looking inside node_modules, reads package.json to find the entry point, and loads the file. Browsers have no such algorithm — they have no file system access, no node_modules convention, and no built-in way to map a bare name like "data-tools" to an actual URL. This is exactly why B is correct: the browser simply doesn't know what URL to fetch, causing the module load to fail even though the ES module syntax is perfectly valid in both environments.
The fix is either an import map (a JSON structure in your HTML that tells the browser "data-tools" maps to a specific URL) or a bundler that resolves everything at build time.
A is wrong because browsers don't restrict ES modules to built-in APIs, and Node.js isn't limited to npm packages — both fully support ES module syntax for any compatible module. C is wrong because browsers don't treat bare specifiers as global variables — they throw a network/resolution error, not a variable lookup. D is wrong because Node.js does not convert ES modules to classic scripts, and browsers don't reject named imports — they handle both perfectly well.
A useful tip: whenever you see a question about cross-environment module compatibility, ask yourself whether specifier resolution rules differ between the environments — that's almost always the root cause.
- Which result should the developer expect in the usual implementations?
Answer: It is generally a window property in the classic browser script but module-scoped in the Node.js CommonJS file.
Whenever you see a question about var declarations across different JavaScript environments, the key is recognizing that where code runs determines what "top-level" actually means — and the answer differs dramatically between browsers and Node.js.
In a classic browser script (loaded via <script> without type="module"), the top-level scope is the global scope. A var declaration there becomes a property on the window object, which is the browser's global object. You can verify this: after running that script, window.sessionLabel === "demo" evaluates to true.
In a Node.js CommonJS module (a .js file loaded with require), Node.js wraps every file in an implicit function — roughly (function(exports, require, module, __filename, __dirname) { ... }). This means your "top-level" code is actually inside a function scope. The var declaration becomes local to that wrapper function, not a property of Node's global object. This is answer C, and it's correct.
A is wrong because it assumes top-level var is universally global — it ignores Node's module wrapper entirely. B is wrong in the opposite direction: it incorrectly claims browser classic scripts isolate their scope, when in fact they attach var declarations to window. D has the two environments exactly backwards — it claims the browser script is module-scoped and Node.js is global, which inverts the actual behavior.
As a study tip, remember: browser classic scripts share the global scope; Node.js CommonJS files don't — Node's wrapper function is the invisible barrier that keeps your variables contained.