1# Mojo JavaScript Bindings API 2This document is a subset of the [Mojo documentation](/mojo/README.md). 3 4[TOC] 5 6## Getting Started 7The bindings API is defined in the `mojo` namespace and implemented in 8`mojo_bindings.js`, which could be generated by the GN target 9`//mojo/public/js:bindings`. 10 11When a Mojom IDL file is processed by the bindings generator, JavaScript code is 12emitted in a `.js` file with the name based on the input `.mojom` file. Suppose 13we create the following Mojom file at 14`//services/echo/public/interfaces/echo.mojom`: 15 16``` 17module test.echo.mojom; 18 19interface Echo { 20 EchoInteger(int32 value) => (int32 result); 21}; 22``` 23 24And a GN target to generate the bindings in 25`//services/echo/public/interfaces/BUILD.gn`: 26 27``` 28import("//mojo/public/tools/bindings/mojom.gni") 29 30mojom("interfaces") { 31 sources = [ 32 "echo.mojom", 33 ] 34} 35``` 36 37Bindings are generated by building one of these implicitly generated targets 38(where "foo" is the target name): 39* `foo_js` JavaScript bindings; used as compile-time dependency. 40* `foo_js_data_deps` JavaScript bindings; used as run-time dependency. 41 42If we then build this target: 43``` 44ninja -C out/r services/echo/public/interfaces:interfaces_js 45``` 46 47This will produce several generated source files. The one relevant to JavaScript 48bindings is: 49``` 50out/gen/services/echo/public/interfaces/echo.mojom.js 51``` 52 53In order to use the definitions in `echo.mojom`, you will need to include two 54files in your html page using `<script>` tags: 55* `mojo_bindings.js` 56 __Note: This file must be included before any `.mojom.js` files.__ 57* `echo.mojom.js` 58 59``` html 60<!DOCTYPE html> 61<script src="URL/to/mojo_bindings.js"></script> 62<script src="URL/to/echo.mojom.js"></script> 63<script> 64 65var echoPtr = new test.echo.mojom.EchoPtr(); 66var echoRequest = mojo.makeRequest(echoPtr); 67// ... 68 69</script> 70``` 71 72## Interfaces 73Similar to the C++ bindings API, we have: 74* `mojo.InterfacePtrInfo` and `mojo.InterfaceRequest` encapsulate two ends of a 75 message pipe. They represent the client end and service end of an interface 76 connection, respectively. 77* For each Mojom interface `Foo`, there is a generated `FooPtr` class. It owns 78 an `InterfacePtrInfo`; provides methods to send interface calls using the 79 message pipe handle from the `InterfacePtrInfo`. 80* `mojo.Binding` owns an `InterfaceRequest`. It listens on the message pipe 81 handle and dispatches incoming messages to a user-defined interface 82 implementation. 83 84Let's consider the `echo.mojom` example above. The following shows how to create 85an `Echo` interface connection and use it to make a call. 86 87``` html 88<!DOCTYPE html> 89<script src="URL/to/mojo_bindings.js"></script> 90<script src="URL/to/echo.mojom.js"></script> 91<script> 92 93function EchoImpl() {} 94EchoImpl.prototype.echoInteger = function(value) { 95 return Promise.resolve({result: value}); 96}; 97 98var echoServicePtr = new test.echo.mojom.EchoPtr(); 99var echoServiceRequest = mojo.makeRequest(echoServicePtr); 100var echoServiceBinding = new mojo.Binding(test.echo.mojom.Echo, 101 new EchoImpl(), 102 echoServiceRequest); 103echoServicePtr.echoInteger({value: 123}).then(function(response) { 104 console.log('The result is ' + response.value); 105}); 106 107</script> 108``` 109 110### Interface Pointers and Requests 111In the example above, `test.echo.mojom.EchoPtr` is an interface pointer class. 112`EchoPtr` represents the client end of an interface connection. For method 113`EchoInteger` in the `Echo` Mojom interface, there is a corresponding 114`echoInteger` method defined in `EchoPtr`. (Please note that the format of the 115generated method name is `camelCaseWithLowerInitial`.) 116 117There are some control methods shared by all interface pointer classes. For 118example, binding/extracting `InterfacePtrInfo`, setting connection error 119handler, querying version information, etc. In order to avoid name collision, 120they are defined in `mojo.InterfacePtrController` and exposed as the `ptr` field 121of every interface pointer class. 122 123In the example above, `echoServiceRequest` is an `InterfaceRequest` instance. It 124represents the service end of an interface connection. 125 126`mojo.makeRequest` creates a message pipe; populates the output argument (which 127could be an `InterfacePtrInfo` or an interface pointer) with one end of the 128pipe; returns the other end wrapped in an `InterfaceRequest` instance. 129 130### Binding an InterfaceRequest 131A `mojo.Binding` bridges an implementation of an interface and a message pipe 132endpoint, dispatching incoming messages to the implementation. 133 134In the example above, `echoServiceBinding` listens for incoming `EchoInteger` 135method calls on the messsage pipe, and dispatches those calls to the `EchoImpl` 136instance. 137 138### Receiving Responses 139Some Mojom interface methods expect a response, such as `EchoInteger`. The 140corresponding JavaScript method returns a Promise. This Promise is resolved when 141the service side sends back a response. It is rejected if the interface is 142disconnected. 143 144### Connection Errors 145If a pipe is disconnected, both endpoints will be able to observe the connection 146error (unless the disconnection is caused by closing/destroying an endpoint, in 147which case that endpoint won't get such a notification). If there are remaining 148incoming messages for an endpoint on disconnection, the connection error won't 149be triggered until the messages are drained. 150 151Pipe disconnecition may be caused by: 152* Mojo system-level causes: process terminated, resource exhausted, etc. 153* The bindings close the pipe due to a validation error when processing a 154 received message. 155* The peer endpoint is closed. For example, the remote side is a bound interface 156 pointer and it is destroyed. 157 158Regardless of the underlying cause, when a connection error is encountered on 159a binding endpoint, that endpoint's **connection error handler** (if set) is 160invoked. This handler may only be invoked *once* as long as the endpoint is 161bound to the same pipe. Typically clients and implementations use this handler 162to do some kind of cleanup or recovery. 163 164``` js 165// Assume echoServicePtr is already bound. 166echoServicePtr.ptr.setConnectionErrorHandler(function() { 167 DoImportantCleanUp(); 168}); 169 170// Assume echoServiceBinding is already bound: 171echoServiceBinding.setConnectionErrorHandler(function() { 172 DoImportantCleanUpToo(); 173}); 174``` 175 176**Note:** Closing one end of a pipe will eventually trigger a connection error 177on the other end. However it's ordered with respect to any other event (*e.g.* 178writing a message) on the pipe. Therefore, it is safe to make an `echoInteger` 179call on `echoServicePtr` and reset it immediately (which results in 180disconnection), `echoServiceBinding` will receive the `echoInteger` call before 181it observes the connection error. 182 183## Associated Interfaces 184An associated interface connection doesn't have its own underlying message pipe. 185It is associated with an existing message pipe (i.e., interface connection). 186 187Similar to the non-associated interface case, we have: 188* `mojo.AssociatedInterfacePtrInfo` and `mojo.AssociatedInterfaceRequest` 189 encapsulate a *route ID*, representing a logical connection over a message 190 pipe. 191* For each Mojom interface `Foo`, there is a generated `FooAssociatedPtr` class. 192 It owns an `AssociatedInterfacePtrInfo`. It is the client side of an 193 interface. 194* `mojo.AssociatedBinding` owns an `AssociatedInterfaceRequest`. It listens on 195 the connection and dispatches incoming messages to a user-defined interface 196 implementation. 197 198See [this document](https://www.chromium.org/developers/design-documents/mojo/associated-interfaces) 199for more details. 200 201## Automatic and Manual Dependency Loading 202By default, generated `.mojom.js` files automatically load Mojom dependencies. 203For example, if `foo.mojom` imports `bar.mojom`, loading `foo.mojom.js` will 204insert a `<script>` tag to load `bar.mojom.js`, if it hasn't been loaded. 205 206The URL of `bar.mojom.js` is determined by: 207* the path of `bar.mojom` relative to the position of `foo.mojom` at build time; 208* the URL of `foo.mojom.js`. 209 210For exmple, if at build time the two Mojom files are located at: 211``` 212a/b/c/foo.mojom 213a/b/d/bar.mojom 214``` 215 216The URL of `foo.mojom.js` is: 217``` 218http://example.org/scripts/b/c/foo.mojom.js 219``` 220 221Then the URL of `bar.mojom.js` is supposed to be: 222``` 223http://example.org/scripts/b/d/bar.mojom.js 224``` 225 226If you would like `bar.mojom.js` to live at a different location, you need to 227set `mojo.config.autoLoadMojomDeps` to `false` before loading `foo.mojom.js`, 228and manually load `bar.mojom.js` yourself. Similarly, you need to turn off this 229option if you merge `bar.mojom.js` and `foo.mojom.js` into a single file. 230 231``` html 232<!-- Automatic dependency loading --> 233<script src="http://example.org/scripts/mojo_bindings.js"></script> 234<script src="http://example.org/scripts/b/c/foo.mojom.js"></script> 235 236 237<!-- Manual dependency loading --> 238<script src="http://example.org/scripts/mojo_bindings.js"></script> 239<script> 240 mojo.config.autoLoadMojomDeps = false; 241</script> 242<script src="http://example.org/scripts/b/d/bar.mojom.js"></script> 243<script src="http://example.org/scripts/b/c/foo.mojom.js"></script> 244``` 245 246### Performance Tip: Avoid Loading the Same .mojom.js File Multiple Times 247If `mojo.config.autoLoadMojomDeps` is set to `true` (which is the default 248value), you might accidentally load the same `.mojom.js` file multiple times if 249you are not careful. Although it doesn't cause fatal errors, it hurts 250performance and therefore should be avoided. 251 252``` html 253<!-- Assume that mojo.config.autoLoadMojomDeps is set to true: --> 254 255<!-- No duplicate loading; recommended. --> 256<script src="http://example.org/scripts/b/c/foo.mojom.js"></script> 257 258<!-- No duplicate loading, although unnecessary. --> 259<script src="http://example.org/scripts/b/d/bar.mojom.js"></script> 260<script src="http://example.org/scripts/b/c/foo.mojom.js"></script> 261 262<!-- Load bar.mojom.js twice; should be avoided. --> 263<!-- when foo.mojom.js is loaded, it sees that bar.mojom.js is not yet loaded, 264 so it inserts another <script> tag for bar.mojom.js. --> 265<script src="http://example.org/scripts/b/c/foo.mojom.js"></script> 266<script src="http://example.org/scripts/b/d/bar.mojom.js"></script> 267``` 268 269If a `.mojom.js` file is loaded for a second time, a warnings will be showed 270using `console.warn()` to bring it to developers' attention. 271 272## Name Formatting 273As a general rule, Mojom definitions follow the C++ formatting style. To make 274the generated JavaScript bindings conforms to our JavaScript style guide, the 275code generator does the following conversions: 276 277| In Mojom | In generated .mojom.js | 278|----------------------|------------------------| 279| MethodLikeThis | methodLikeThis 280| parameter_like_this | parameterLikeThis 281| field_like_this | fieldLikeThis 282| name_space.like_this | nameSpace.likeThis 283