Skip to content

Commit

Permalink
Rewrite Error.p.stack (mdn#30908)
Browse files Browse the repository at this point in the history
* Rewrite Error.p.stack

* Apply suggestions from code review

Co-authored-by: Chris Mills <chrisdavidmills@gmail.com>

* Update files/en-us/web/javascript/reference/global_objects/error/stack/index.md

* Update files/en-us/web/javascript/reference/global_objects/error/stack/index.md

Co-authored-by: Chris Mills <chrisdavidmills@gmail.com>

---------

Co-authored-by: Chris Mills <chrisdavidmills@gmail.com>
  • Loading branch information
2 people authored and dipikabh committed Jan 17, 2024
1 parent 8d3effd commit c6e0b5a
Showing 1 changed file with 100 additions and 69 deletions.
169 changes: 100 additions & 69 deletions files/en-us/web/javascript/reference/global_objects/error/stack/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ browser-compat: javascript.builtins.Error.stack

{{JSRef}} {{Non-standard_Header}}

> **Note:** The `stack` property is de facto implemented by all major JavaScript engines, and [the JavaScript standards committee is looking to standardize it](https://github.com/tc39/proposal-error-stacks). You cannot rely on the precise content of the stack string due to implementation inconsistencies, but you can generally assume it exists and use it for debugging purposes.
The non-standard **`stack`** property of an {{jsxref("Error")}} instance offers a trace of which functions were called, in what order, from which line and file, and with what arguments. The stack string proceeds from the most recent calls to earlier ones, leading back to the original global scope call.

## Value
Expand All @@ -24,100 +26,129 @@ Because the `stack` property is non-standard, implementations differ about where

## Description

Each step will be separated by a newline, with the first part of the line being the function name (if not a call from the global scope), then by an at (@) sign, the file location (except when the function is the error constructor as the error is being thrown), a colon, and, if there is a file location, the line number. (Note that the {{jsxref("Error")}} object also possesses the `fileName`, `lineNumber` and `columnNumber` properties for retrieving these from the error thrown (but only the error, and not its trace).)
Each JavaScript engine uses its own format for stack traces, but they are fairly consistent in their high-level structure. Every implementation uses a separate line in the stack to represent each function call. The call that directly caused the error is placed at the top, and the call that started the whole call chain is placed at the bottom. Below are some examples of stack traces:

Note that this is the format used by Firefox. There is no standard formatting. However, Safari 6+ and Opera 12- use a very similar format. Browsers using the V8 JavaScript engine (such as Chrome, Opera 15+, Android Browser) and IE10+, on the other hand, uses a different format.
```js
function foo() {
bar();
}

**Argument values in the stack**: Prior to Firefox 14, the function name would be followed by the argument values converted to string in parentheses immediately before the at (`@`) sign. While an object (or array, etc.) would appear in the converted form `"[object Object]"`, and as such could not be evaluated back into the actual objects, scalar values could be retrieved (though it may be — it is still possible in Firefox 14 — easier to use `arguments.callee.caller.arguments`, as could the function name be retrieved by `arguments.callee.caller.name`). `"undefined"` is listed as `"(void 0)"`. Note that if string arguments were passed in with values such as `"@"`, `"("`, `")"` (or if in file names), you could not easily rely on these for breaking the line into its component parts. Thus, in Firefox 14 and later this is less of an issue.
function bar() {
baz();
}

Different browsers set this value at different times. For example, Firefox sets it when creating an {{jsxref("Error")}} object, while PhantomJS sets it only when throwing the {{jsxref("Error")}}, and [archived MSDN docs](https://web.archive.org/web/20180618201428/https://docs.microsoft.com/scripting/javascript/reference/stack-property-error-javascript) also seem to match the PhantomJS implementation.
function baz() {
console.log(new Error().stack);
}

## Examples
foo();
```

### Using the stack property
```plain
#### JavaScriptCore
baz@filename.js:10:24
bar@filename.js:6:6
foo@filename.js:2:6
global code@filename.js:13:4
#### SpiderMonkey
baz@filename.js:10:15
bar@filename.js:6:3
foo@filename.js:2:3
@filename.js:13:1
#### V8
Error
at baz (filename.js:10:15)
at bar (filename.js:6:3)
at foo (filename.js:2:3)
at filename.js:13:1
```

Different engines set this value at different times. Most modern engines set it when the {{jsxref("Error")}} object is created. This means you can get the full call stack information within a function using the following:

The following HTML markup demonstrates the use of `stack` property.

```html
<!doctype html>
<meta charset="UTF-8" />
<title>Stack Trace Example</title>
<body>
<script>
function trace() {
try {
throw new Error("myError");
} catch (e) {
alert(e.stack);
}
}
function b() {
trace();
}
function a() {
b(3, 4, "\n\n", undefined, {});
}
a("first call, firstarg");
</script>
</body>
```js
function foo() {
console.log(new Error().stack);
}
```

Assuming the above markup is saved as `C:\example.html` on a Windows file system it produces an alert message box with the following text:
Without having to throw an error and then catch it.

Starting with Firefox 30 and later containing the column number:
In V8, the non-standard `Error.captureStackTrace()`, `Error.stackTraceLimit`, and `Error.prepareStackTrace()` APIs can be used to customize the stack trace. Read the [Stack trace API](https://v8.dev/docs/stack-trace-api) in the V8 docs for more information.

```plain
trace@file:///C:/example.html:9:17
b@file:///C:/example.html:16:13
a@file:///C:/example.html:19:13
@file:///C:/example.html:21:9
```
Stack frames can be things other than explicit function calls, too. For example, event listeners, timeout jobs, and promise handlers all begin their own call chain. Source code within {{jsxref("Global_Objects/eval", "eval()")}} and {{jsxref("Function")}} constructor calls also appear in the stack:

Firefox 14 to Firefox 29:
```js
console.log(new Function("return new Error('Function failed')")().stack);
console.log("====");
console.log(eval("new Error('eval failed')").stack);
```

```plain
trace@file:///C:/example.html:9
b@file:///C:/example.html:16
a@file:///C:/example.html:19
@file:///C:/example.html:21
#### JavaScriptCore
anonymous@
global code@filename.js:1:65
====
eval code@
eval@[native code]
global code@filename.js:3:17
#### SpiderMonkey
anonymous@filename.js line 1 > Function:1:8
@filename.js:1:65
====
@filename.js line 3 > eval:1:1
@filename.js:3:13
#### V8
Error: Function failed
at eval (eval at <anonymous> (filename.js:1:13), <anonymous>:1:8)
at filename.js:1:65
====
Error: eval failed
at eval (eval at <anonymous> (filename.js:3:13), <anonymous>:1:1)
at filename.js:3:13
```

Firefox 13 and earlier would instead produce the following text:
In Firefox, you can use the `//# sourceURL` directive to name an eval source. See the Firefox [Debug eval sources](https://firefox-source-docs.mozilla.org/devtools-user/debugger/how_to/debug_eval_sources/index.html) docs and the [Naming `eval` Scripts with the `//# sourceURL` Directive](https://fitzgeraldnick.com/2014/12/05/name-eval-scripts.html) blog post for more details.

```plain
Error("myError")@:0
trace()@file:///C:/example.html:9
b(3,4,"\n\n",(void 0),[object Object])@file:///C:/example.html:16
a("first call, firstarg")@file:///C:/example.html:19
@file:///C:/example.html:21
```
## Examples

### Stack of eval'ed code
### Using the stack property

Starting with Firefox 30, the error stack of code in `Function()` and `eval()` calls, now produces stacks with more detailed information about the line and column numbers inside these calls. Function calls are indicated with `"> Function"` and eval calls with `"> eval"`.
The following script demonstrates how to use the `stack` property to output a stack trace into your browser window. You can use this to check what your browser's stack structure looks like.

```js
try {
new Function("throw new Error()")();
} catch (e) {
console.log(e.stack);
}
```html hidden
<div id="output"></div>
```

// anonymous@file:///C:/example.html line 7 > Function:1:1
// @file:///C:/example.html:7:6
```css hidden
#output {
white-space: pre;
font-family: monospace;
}
```

```js
function trace() {
throw new Error("trace() failed");
}
function b() {
trace();
}
function a() {
b(3, 4, "\n\n", undefined, {});
}
try {
eval("eval('FAIL')");
} catch (x) {
console.log(x.stack);
a("first call, firstarg");
} catch (e) {
document.getElementById("output").textContent = e.stack;
}

// @file:///C:/example.html line 7 > eval line 1 > eval:1:1
// @file:///C:/example.html line 7 > eval:1:1
// @file:///C:/example.html:7:6
```

You can also use the `//# sourceURL` directive to name an eval source. See also [Debug eval sources](https://firefox-source-docs.mozilla.org/devtools-user/debugger/how_to/debug_eval_sources/index.html) in the [Debugger](https://firefox-source-docs.mozilla.org/devtools-user/debugger/index.html) docs and this [blog post](https://fitzgeraldnick.com/2014/12/05/name-eval-scripts.html).
{{EmbedLiveSample("Using_the_stack_property", "700", "200")}}

## Specifications

Expand Down

0 comments on commit c6e0b5a

Please # to comment.