0

TL;DR - How can I determine which anonymous function a thrown error came from?

See: https://jsfiddle.net/xhj1Ld3n/

Which works in chrome, but not firefox


Long version:

I am making a JS game that allows players to write dynamic Javascript. The player-provided code is put into a Function() which is executed.

The problem is that if the player makes a typo (which causes an error to be thrown) it's hard to get 2 pieces of information which I want to present to the player:

  1. Which line number in the player-provided function triggered the error

  2. Which player-provided function triggered the error (the player can provide more than 1)

I solved number 1 by doing:

window.onerror = function(message, source, lineno, colno, error) { 
   // get line number from lineno
}

This seemed like the easiest way to get the line number from an error without doing browser-specific parsing of error.stack.

Now I'm trying to figure out how to determine which player-provided function it came from.

Initially I tried giving the player provided functions names with Object.defineProperty so that I could then parse out the name from the error stack:

Object.defineProperty(playerFn, "name", {value: "playerFn1"});

However, while this works in Chrome:

ReferenceError: x is not defined
    at playerFn1 (eval at executePlayerCode (game.js:370), <anonymous>:22:1)
    ...

in Firefox it looks like this:

ReferenceError: x is not defined
    anonymous http://localhost:8000/js/game.js line 370 > Function:22
    ...

So it looks like changing the Function name only has an effect on the error stack in Chrome, not Firefox.

My question is... is there a somewhat portable method I can use to identify which Function() a given thrown error is referring to?

I tried wrapping the player-provided code with a try/catch that injects additional context into the error before re-throwing, but in Chrome this corrupts the line number in window.error with the rethrow line number, not the original throw line number.

Gillespie
  • 5,780
  • 3
  • 32
  • 54
  • Wouldn't than using `error.stack` be a more universal way than `window.error`? – vanowm Sep 06 '21 at 20:56
  • I guess the ES5 answers to [Is there any non-eval way to create a function with a runtime-determined name?](https://stackoverflow.com/q/9479046/1048572) would solve your naming problem? – Bergi Sep 06 '21 at 21:00
  • If I use `error.stack` wouldn't I have to implement N different ways (one per browser) of parsing out the line and column number since each browser is different? – Gillespie Sep 06 '21 at 21:00
  • @Bergi "This is implemented in all modern browsers, although Edge and Safari don't use the name in stack traces" I don't care about IE, but I was hoping it would work in most modern browsers – Gillespie Sep 06 '21 at 21:05
  • I can confirm it does work in Edge, don't have a mac so I don't know about Safari, but this is probably as good as it's going to get. Thanks – Gillespie Sep 06 '21 at 21:14
  • 1
    @Gillespie I explicitly referred to the ES5 answers, not the ES6 bit at the top of the accepted answer. – Bergi Sep 06 '21 at 21:16
  • @Bergi Ahh, my mistake, I didn't pay close enough attention to your comment. – Gillespie Sep 06 '21 at 21:46
  • You could give the function a name, even if it is being assigned to another variable, so that the error stack will tell you the exact function that is causing the error – Kenneth Lew Sep 06 '21 at 22:33

0 Answers0