# Mojo JavaScript Bindings API This document is a subset of the [Mojo documentation](/mojo/README.md). [TOC] ## Getting Started The bindings API is defined in the `mojo` namespace and implemented in `mojo_bindings.js`, which could be generated by the GN target `//mojo/public/js:bindings`. When a Mojom IDL file is processed by the bindings generator, JavaScript code is emitted in a `.js` file with the name based on the input `.mojom` file. Suppose we create the following Mojom file at `//services/echo/public/interfaces/echo.mojom`: ``` module test.echo.mojom; interface Echo { EchoInteger(int32 value) => (int32 result); }; ``` And a GN target to generate the bindings in `//services/echo/public/interfaces/BUILD.gn`: ``` import("//mojo/public/tools/bindings/mojom.gni") mojom("interfaces") { sources = [ "echo.mojom", ] } ``` Bindings are generated by building one of these implicitly generated targets (where "foo" is the target name): * `foo_js` JavaScript bindings; used as compile-time dependency. * `foo_js_data_deps` JavaScript bindings; used as run-time dependency. If we then build this target: ``` ninja -C out/r services/echo/public/interfaces:interfaces_js ``` This will produce several generated source files. The one relevant to JavaScript bindings is: ``` out/gen/services/echo/public/interfaces/echo.mojom.js ``` In order to use the definitions in `echo.mojom`, you will need to include two files in your html page using `<script>` tags: * `mojo_bindings.js` __Note: This file must be included before any `.mojom.js` files.__ * `echo.mojom.js` ``` html <!DOCTYPE html> <script src="URL/to/mojo_bindings.js"></script> <script src="URL/to/echo.mojom.js"></script> <script> var echoPtr = new test.echo.mojom.EchoPtr(); var echoRequest = mojo.makeRequest(echoPtr); // ... </script> ``` ## Interfaces Similar to the C++ bindings API, we have: * `mojo.InterfacePtrInfo` and `mojo.InterfaceRequest` encapsulate two ends of a message pipe. They represent the client end and service end of an interface connection, respectively. * For each Mojom interface `Foo`, there is a generated `FooPtr` class. It owns an `InterfacePtrInfo`; provides methods to send interface calls using the message pipe handle from the `InterfacePtrInfo`. * `mojo.Binding` owns an `InterfaceRequest`. It listens on the message pipe handle and dispatches incoming messages to a user-defined interface implementation. Let's consider the `echo.mojom` example above. The following shows how to create an `Echo` interface connection and use it to make a call. ``` html <!DOCTYPE html> <script src="URL/to/mojo_bindings.js"></script> <script src="URL/to/echo.mojom.js"></script> <script> function EchoImpl() {} EchoImpl.prototype.echoInteger = function(value) { return Promise.resolve({result: value}); }; var echoServicePtr = new test.echo.mojom.EchoPtr(); var echoServiceRequest = mojo.makeRequest(echoServicePtr); var echoServiceBinding = new mojo.Binding(test.echo.mojom.Echo, new EchoImpl(), echoServiceRequest); echoServicePtr.echoInteger({value: 123}).then(function(response) { console.log('The result is ' + response.value); }); </script> ``` ### Interface Pointers and Requests In the example above, `test.echo.mojom.EchoPtr` is an interface pointer class. `EchoPtr` represents the client end of an interface connection. For method `EchoInteger` in the `Echo` Mojom interface, there is a corresponding `echoInteger` method defined in `EchoPtr`. (Please note that the format of the generated method name is `camelCaseWithLowerInitial`.) There are some control methods shared by all interface pointer classes. For example, binding/extracting `InterfacePtrInfo`, setting connection error handler, querying version information, etc. In order to avoid name collision, they are defined in `mojo.InterfacePtrController` and exposed as the `ptr` field of every interface pointer class. In the example above, `echoServiceRequest` is an `InterfaceRequest` instance. It represents the service end of an interface connection. `mojo.makeRequest` creates a message pipe; populates the output argument (which could be an `InterfacePtrInfo` or an interface pointer) with one end of the pipe; returns the other end wrapped in an `InterfaceRequest` instance. ### Binding an InterfaceRequest A `mojo.Binding` bridges an implementation of an interface and a message pipe endpoint, dispatching incoming messages to the implementation. In the example above, `echoServiceBinding` listens for incoming `EchoInteger` method calls on the messsage pipe, and dispatches those calls to the `EchoImpl` instance. ### Receiving Responses Some Mojom interface methods expect a response, such as `EchoInteger`. The corresponding JavaScript method returns a Promise. This Promise is resolved when the service side sends back a response. It is rejected if the interface is disconnected. ### Connection Errors If a pipe is disconnected, both endpoints will be able to observe the connection error (unless the disconnection is caused by closing/destroying an endpoint, in which case that endpoint won't get such a notification). If there are remaining incoming messages for an endpoint on disconnection, the connection error won't be triggered until the messages are drained. Pipe disconnecition may be caused by: * Mojo system-level causes: process terminated, resource exhausted, etc. * The bindings close the pipe due to a validation error when processing a received message. * The peer endpoint is closed. For example, the remote side is a bound interface pointer and it is destroyed. Regardless of the underlying cause, when a connection error is encountered on a binding endpoint, that endpoint's **connection error handler** (if set) is invoked. This handler may only be invoked *once* as long as the endpoint is bound to the same pipe. Typically clients and implementations use this handler to do some kind of cleanup or recovery. ``` js // Assume echoServicePtr is already bound. echoServicePtr.ptr.setConnectionErrorHandler(function() { DoImportantCleanUp(); }); // Assume echoServiceBinding is already bound: echoServiceBinding.setConnectionErrorHandler(function() { DoImportantCleanUpToo(); }); ``` **Note:** Closing one end of a pipe will eventually trigger a connection error on the other end. However it's ordered with respect to any other event (*e.g.* writing a message) on the pipe. Therefore, it is safe to make an `echoInteger` call on `echoServicePtr` and reset it immediately (which results in disconnection), `echoServiceBinding` will receive the `echoInteger` call before it observes the connection error. ## Associated Interfaces An associated interface connection doesn't have its own underlying message pipe. It is associated with an existing message pipe (i.e., interface connection). Similar to the non-associated interface case, we have: * `mojo.AssociatedInterfacePtrInfo` and `mojo.AssociatedInterfaceRequest` encapsulate a *route ID*, representing a logical connection over a message pipe. * For each Mojom interface `Foo`, there is a generated `FooAssociatedPtr` class. It owns an `AssociatedInterfacePtrInfo`. It is the client side of an interface. * `mojo.AssociatedBinding` owns an `AssociatedInterfaceRequest`. It listens on the connection and dispatches incoming messages to a user-defined interface implementation. See [this document](https://www.chromium.org/developers/design-documents/mojo/associated-interfaces) for more details. ## Automatic and Manual Dependency Loading By default, generated `.mojom.js` files automatically load Mojom dependencies. For example, if `foo.mojom` imports `bar.mojom`, loading `foo.mojom.js` will insert a `<script>` tag to load `bar.mojom.js`, if it hasn't been loaded. The URL of `bar.mojom.js` is determined by: * the path of `bar.mojom` relative to the position of `foo.mojom` at build time; * the URL of `foo.mojom.js`. For exmple, if at build time the two Mojom files are located at: ``` a/b/c/foo.mojom a/b/d/bar.mojom ``` The URL of `foo.mojom.js` is: ``` http://example.org/scripts/b/c/foo.mojom.js ``` Then the URL of `bar.mojom.js` is supposed to be: ``` http://example.org/scripts/b/d/bar.mojom.js ``` If you would like `bar.mojom.js` to live at a different location, you need to set `mojo.config.autoLoadMojomDeps` to `false` before loading `foo.mojom.js`, and manually load `bar.mojom.js` yourself. Similarly, you need to turn off this option if you merge `bar.mojom.js` and `foo.mojom.js` into a single file. ``` html <!-- Automatic dependency loading --> <script src="http://example.org/scripts/mojo_bindings.js"></script> <script src="http://example.org/scripts/b/c/foo.mojom.js"></script> <!-- Manual dependency loading --> <script src="http://example.org/scripts/mojo_bindings.js"></script> <script> mojo.config.autoLoadMojomDeps = false; </script> <script src="http://example.org/scripts/b/d/bar.mojom.js"></script> <script src="http://example.org/scripts/b/c/foo.mojom.js"></script> ``` ### Performance Tip: Avoid Loading the Same .mojom.js File Multiple Times If `mojo.config.autoLoadMojomDeps` is set to `true` (which is the default value), you might accidentally load the same `.mojom.js` file multiple times if you are not careful. Although it doesn't cause fatal errors, it hurts performance and therefore should be avoided. ``` html <!-- Assume that mojo.config.autoLoadMojomDeps is set to true: --> <!-- No duplicate loading; recommended. --> <script src="http://example.org/scripts/b/c/foo.mojom.js"></script> <!-- No duplicate loading, although unnecessary. --> <script src="http://example.org/scripts/b/d/bar.mojom.js"></script> <script src="http://example.org/scripts/b/c/foo.mojom.js"></script> <!-- Load bar.mojom.js twice; should be avoided. --> <!-- when foo.mojom.js is loaded, it sees that bar.mojom.js is not yet loaded, so it inserts another <script> tag for bar.mojom.js. --> <script src="http://example.org/scripts/b/c/foo.mojom.js"></script> <script src="http://example.org/scripts/b/d/bar.mojom.js"></script> ``` If a `.mojom.js` file is loaded for a second time, a warnings will be showed using `console.warn()` to bring it to developers' attention. ## Name Formatting As a general rule, Mojom definitions follow the C++ formatting style. To make the generated JavaScript bindings conforms to our JavaScript style guide, the code generator does the following conversions: | In Mojom | In generated .mojom.js | |----------------------|------------------------| | MethodLikeThis | methodLikeThis | parameter_like_this | parameterLikeThis | field_like_this | fieldLikeThis | name_space.like_this | nameSpace.likeThis