• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..--

lib/23-Nov-2023-3,2302,487

README.mdD23-Nov-202310.6 KiB283228

base.jsD23-Nov-20234.2 KiB13570

bindings.jsD23-Nov-202317 KiB549371

interface_types.jsD23-Nov-20232.9 KiB9870

mojo_bindings_resources.grdD23-Nov-2023841 2221

README.md

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