1 # Mojo JavaScript Bindings API
2 This document is a subset of the [Mojo documentation](/mojo/README.md).
3
4 [TOC]
5
6 ## Getting Started
7 The 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
11 When a Mojom IDL file is processed by the bindings generator, JavaScript code is
12 emitted in a `.js` file with the name based on the input `.mojom` file. Suppose
13 we create the following Mojom file at
14 `//services/echo/public/interfaces/echo.mojom`:
15
16 ```
17 module test.echo.mojom;
18
19 interface Echo {
20 EchoInteger(int32 value) => (int32 result);
21 };
22 ```
23
24 And a GN target to generate the bindings in
25 `//services/echo/public/interfaces/BUILD.gn`:
26
27 ```
28 import("//mojo/public/tools/bindings/mojom.gni")
29
30 mojom("interfaces") {
31 sources = [
32 "echo.mojom",
33 ]
34 }
35 ```
36
37 Bindings 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
42 If we then build this target:
43 ```
44 ninja -C out/r services/echo/public/interfaces:interfaces_js
45 ```
46
47 This will produce several generated source files. The one relevant to JavaScript
48 bindings is:
49 ```
50 out/gen/services/echo/public/interfaces/echo.mojom.js
51 ```
52
53 In order to use the definitions in `echo.mojom`, you will need to include two
54 files 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
65 var echoPtr = new test.echo.mojom.EchoPtr();
66 var echoRequest = mojo.makeRequest(echoPtr);
67 // ...
68
69 </script>
70 ```
71
72 ## Interfaces
73 Similar 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
84 Let's consider the `echo.mojom` example above. The following shows how to create
85 an `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
93 function EchoImpl() {}
94 EchoImpl.prototype.echoInteger = function(value) {
95 return Promise.resolve({result: value});
96 };
97
98 var echoServicePtr = new test.echo.mojom.EchoPtr();
99 var echoServiceRequest = mojo.makeRequest(echoServicePtr);
100 var echoServiceBinding = new mojo.Binding(test.echo.mojom.Echo,
101 new EchoImpl(),
102 echoServiceRequest);
103 echoServicePtr.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
111 In 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
115 generated method name is `camelCaseWithLowerInitial`.)
116
117 There are some control methods shared by all interface pointer classes. For
118 example, binding/extracting `InterfacePtrInfo`, setting connection error
119 handler, querying version information, etc. In order to avoid name collision,
120 they are defined in `mojo.InterfacePtrController` and exposed as the `ptr` field
121 of every interface pointer class.
122
123 In the example above, `echoServiceRequest` is an `InterfaceRequest` instance. It
124 represents the service end of an interface connection.
125
126 `mojo.makeRequest` creates a message pipe; populates the output argument (which
127 could be an `InterfacePtrInfo` or an interface pointer) with one end of the
128 pipe; returns the other end wrapped in an `InterfaceRequest` instance.
129
130 ### Binding an InterfaceRequest
131 A `mojo.Binding` bridges an implementation of an interface and a message pipe
132 endpoint, dispatching incoming messages to the implementation.
133
134 In the example above, `echoServiceBinding` listens for incoming `EchoInteger`
135 method calls on the messsage pipe, and dispatches those calls to the `EchoImpl`
136 instance.
137
138 ### Receiving Responses
139 Some Mojom interface methods expect a response, such as `EchoInteger`. The
140 corresponding JavaScript method returns a Promise. This Promise is resolved when
141 the service side sends back a response. It is rejected if the interface is
142 disconnected.
143
144 ### Connection Errors
145 If a pipe is disconnected, both endpoints will be able to observe the connection
146 error (unless the disconnection is caused by closing/destroying an endpoint, in
147 which case that endpoint won't get such a notification). If there are remaining
148 incoming messages for an endpoint on disconnection, the connection error won't
149 be triggered until the messages are drained.
150
151 Pipe 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
158 Regardless of the underlying cause, when a connection error is encountered on
159 a binding endpoint, that endpoint's **connection error handler** (if set) is
160 invoked. This handler may only be invoked *once* as long as the endpoint is
161 bound to the same pipe. Typically clients and implementations use this handler
162 to do some kind of cleanup or recovery.
163
164 ``` js
165 // Assume echoServicePtr is already bound.
166 echoServicePtr.ptr.setConnectionErrorHandler(function() {
167 DoImportantCleanUp();
168 });
169
170 // Assume echoServiceBinding is already bound:
171 echoServiceBinding.setConnectionErrorHandler(function() {
172 DoImportantCleanUpToo();
173 });
174 ```
175
176 **Note:** Closing one end of a pipe will eventually trigger a connection error
177 on the other end. However it's ordered with respect to any other event (*e.g.*
178 writing a message) on the pipe. Therefore, it is safe to make an `echoInteger`
179 call on `echoServicePtr` and reset it immediately (which results in
180 disconnection), `echoServiceBinding` will receive the `echoInteger` call before
181 it observes the connection error.
182
183 ## Associated Interfaces
184 An associated interface connection doesn't have its own underlying message pipe.
185 It is associated with an existing message pipe (i.e., interface connection).
186
187 Similar 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
198 See [this document](https://www.chromium.org/developers/design-documents/mojo/associated-interfaces)
199 for more details.
200
201 ## Automatic and Manual Dependency Loading
202 By default, generated `.mojom.js` files automatically load Mojom dependencies.
203 For example, if `foo.mojom` imports `bar.mojom`, loading `foo.mojom.js` will
204 insert a `<script>` tag to load `bar.mojom.js`, if it hasn't been loaded.
205
206 The 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
210 For exmple, if at build time the two Mojom files are located at:
211 ```
212 a/b/c/foo.mojom
213 a/b/d/bar.mojom
214 ```
215
216 The URL of `foo.mojom.js` is:
217 ```
218 http://example.org/scripts/b/c/foo.mojom.js
219 ```
220
221 Then the URL of `bar.mojom.js` is supposed to be:
222 ```
223 http://example.org/scripts/b/d/bar.mojom.js
224 ```
225
226 If you would like `bar.mojom.js` to live at a different location, you need to
227 set `mojo.config.autoLoadMojomDeps` to `false` before loading `foo.mojom.js`,
228 and manually load `bar.mojom.js` yourself. Similarly, you need to turn off this
229 option 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
247 If `mojo.config.autoLoadMojomDeps` is set to `true` (which is the default
248 value), you might accidentally load the same `.mojom.js` file multiple times if
249 you are not careful. Although it doesn't cause fatal errors, it hurts
250 performance 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
269 If a `.mojom.js` file is loaded for a second time, a warnings will be showed
270 using `console.warn()` to bring it to developers' attention.
271
272 ## Name Formatting
273 As a general rule, Mojom definitions follow the C++ formatting style. To make
274 the generated JavaScript bindings conforms to our JavaScript style guide, the
275 code 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