Is it possible to generate a JS error from Go web assembly?

I attempted

js.Global().Call("throw", "yeet")

However, I encountered

panic: 1:1: expected operand, found 'type' [recovered] wasm_exec.f7bab17184626fa7f3ebe6c157d4026825842d39bfae444ef945e60ec7d3b0f1.js:51 panic: syscall/js: Value.Call: property throw is not a function, got undefined

It appears that there is an Error type specified in syscall/js, yet there is no mention of how to throw it https://golang.org/pkg/syscall/js/#Error

Answer №1

WebAssembly does not allow for throwing JS errors directly. In JavaScript, throwing a value triggers the runtime to unwind the stack to the nearest try block or log an uncaught error. The execution of WASM happens in a sandboxed environment separate from the JS stack, as outlined in the WebAssembly docs:

Each WebAssembly module operates within a secure environment isolated from the host runtime using fault isolation techniques.

If a WASM function calls into JS code that throws an error, the WASM runtime treats it like a panic situation. While WASM does have access to traps, they are designed to halt execution at the runtime level and are not supported by Go's syscall/js module.

The recommended way to handle potentially failing code execution is by returning a Promise. This allows you to either resolve the promise on success or reject it on failure. The calling JS code can then await the promise execution within a try/catch block or use promise chaining with a .catch() callback. Here is a brief example:

func main() {
    c := make(chan struct{})

    js.Global().Set("doSomething", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
        handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
            resolve := args[0]
            reject := args[1]

            go func() {
                data, err := doSomeWork()
                if err != nil {
                    // err should be an instance of `error`, eg `errors.New("some error")`
                    errorConstructor := js.Global().Get("Error")
                    errorObject := errorConstructor.New(err.Error())
                    reject.Invoke(errorObject)
                } else {
                    resolve.Invoke(js.ValueOf(data))
                }
            }()

            return nil
        })

        promiseConstructor := js.Global().Get("Promise")
        return promiseConstructor.New(handler)
    })

    <-c
}

Then, in your JS code:

(async () => {
  try {
    await window.doSomething();
  } catch (err) {
    console.log('caught error from WASM:', err);
  }
}();

or

window.doSomething()
  .then(_ => /* ... */)
  .catch(err => {
    console.log('caught error from WASM:', err);
  });

Answer №2

My perspective differs from @superhawk610 on this matter

Throwing a JS error from WebAssembly is not something that can be easily done

While it is technically possible to throw an error, the practicality of it may be questionable. In most cases, implementing some Promise logic as suggested by @superhawk610 would be more reasonable. However, if you are determined to throw an exception, here is a simple example.

example

1. Create a throw function stub

// Throw function stub for throwing javascript exceptions
// No implementation!
func Throw(exception string, message string)

2. Provide assembler hint with yourpkg_js.s file

// Implementation for throwing javascript exceptions
TEXT ·Throw(SB), NOSPLIT, $0
  CallImport
  RET

3. Extend wasm_exec / your wasm importObject with a js callback

this.importObject = {
  go: {
    // ...

    // func Throw(exception string, message string)
    '<your-pkg-import-path>.Throw': (sp) => {
      const exception = loadString(sp + 8)
      const message = loadString(sp + 24)
      const throwable = globalThis[exception](message)
      throw throwable
    }
  }
}

Now you can throw errors using the Error class name and a custom message. For example:

func main () {
  Throw("TypeError", "invalid arguments")
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Saving an item in the state following a function execution

Please forgive any rough language. Taking a look at the question should only take around 30 seconds. The code snippet below is what I'm working with: constructor(props) { super(props); this.state = { report: [], ...

Conceal on External Click with AngularJS

My code looks something like this... I am using the 'left-menu-active' class to toggle the menu in css... I have two issues and I am looking to resolve them using angular js... I want to dynamically add a class to the parent element using angu ...

I keep encountering a 404 error page not found whenever I try to use the useRouter function. What could

Once the form is submitted by the user, I want them to be redirected to a thank you page. However, when the backend logic is executed, it redirects me to a 404 page. I have checked the URL path and everything seems to be correct. The structure of my proje ...

JavaScript code that exhibits a sandwich pattern

My apologies if the title of the question is misleading. I am actually seeking the JavaScript equivalent of the following Python code: ## python code def call_with_context(fn, *args): ## code to create context, e.g. profiling, db.connect, or drawing co ...

Asynchronous JavaScript combined with a for loop

I'm interested in accomplishing a straightforward task using Nodejs and Async. Let's say I have a total of pages, which is 4 in this example. I am looking to send a request 4 times and then execute a callback once all responses have been receive ...

What is the best way to conceal the dt tag when the dd tag contains no value

Is there a way to hide the "Subject" if the "subject_title" field is empty? <dt class="col-sm-6 text-dark" >Subject</dt> <dd class="col-sm-6">{{$course_dtl->subject_title }}</dd> For example, I would li ...

Sending properties through the React Router to a specific component

Within my component, I have a material table that triggers a function when the edit button is clicked: //MaterialTable.js ... const handleEdit = (e, Data) => { console.log(Data) return(<EditFunction id={Data.id} />) ... The purpose of ...

Utilizing CSS to showcase various sections of a webpage

Here is a basic example of an HTML file available at this link: http://jsfiddle.net/WhupP/2/ The webpage consists of 4 main sections - header, left-column, righ-column, and footer. Additionally, there are 2 @media elements named screen and print. When att ...

Issue: Unable to reach essential Node.js modules

After attempting to deploy Next.js on Cloudflare Pages, I encountered the following error: Error: Could not access built-in Node.js modules. It is recommended to ensure that your Cloudflare Pages project has the 'nodejs_compat' compatibility flag ...

An error has been detected by Internet Explorer 8 at line number 373402504

Internet Explorer 8 is throwing an error message that seems to be from a different galaxy ("Expected identifier, string or number") at a line number that makes no sense. Surprisingly, the code functions perfectly on FireFox. Checking the source code, I se ...

Showing error messages to users with Angular and Firebase

As a beginner in Angular JS, html, and css, I am facing a challenge with routing in my login component. When the user clicks submit, the application should redirect to the landing page upon successful authentication or return to the login page with an erro ...

Guide to troubleshooting JavaScript in Firefox using Visual Studio 2008?

In the header section of my ASPX page, I have some scripts that I would like to debug with breakpoints in Firefox. ...

What is the best way to determine the position of an internal SVG element in relation to the viewport of an outer SVG element?

Consider an SVG element with various components: <div style="margin-left:50px; width: 100%; min-height: 400px;"> <svg> <g transform="translate(34.34,47.5) scale(0.345)" height="100%" width="100%"> <svg x="20" y ="50" style ...

What is the best way to transfer a JavaScript variable to a PHP file and then store it in a PHP variable?

I am working on a webpage that displays multiple images, each of which can be replaced by another image in the same location. Adjacent to each image is a form where users can upload the new image. One important requirement is that the newly uploaded image ...

How to display a variety of JSON data in different templates with unique variables using angularjs

I am curious about the best approach to handling a response that contains various types of objects presented like this: [ {"nodeClass":"Entity", "text":"foo","entityfield":"booz"}, {"nodeClass":"User","username":"bar","userfield":"baz"} ] Each type of ob ...

Issue encountered while trying to retrieve element within unnamed function in ajax system

Is there a way to fetch data from a file using Ajax when mousing over an element? My code seems to be working fine, but I'm having trouble accessing a <p> element inside an anonymous function. It seems like the element loses scope within the fun ...

Issue with Javascript/Jquery functionality within a PHP script

I have been attempting to incorporate a multi-select feature (view at http://jsfiddle.net/eUDRV/318/) into my PHP webpage. While I am able to display the table as desired, pressing the buttons to move elements from one side to another does not trigger any ...

Creating routes in Node.js after setting up middleware

Currently tackling a project using node.js and encountering a specific issue. After setting up all routes with express (app.get("..", func)), I find myself stuck with a middleware that catches all requests and redirects to a 404-page. The problem arises w ...

Enhance JavaScript by incorporating the selected value of an HTML dropdown menu

My code is as follows: <select name="points"> <option value="5">5 points</option> <option value="10">10 points</option> <option value="50">50 points</option> </select> This is my JavaScript code: < ...

The system does not acknowledge 'CI' as a command that can be used internally or externally, functioning program, or batch file

Every time I attempt to execute npm run build in my React project, a persistent error keeps popping up: 'CI' is not recognized as an internal or external command, operable program or batch file. I have exhausted all troubleshooting steps - fro ...