Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(616)

Side by Side Diff: examples/js/README.md

Issue 803173009: Mojo JS Bindings: Eliminate foo$ Stub and Proxy class members (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: sync Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | examples/js/users-guide.md » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 JavaScript Mojo Example Applications 1 JavaScript Mojo Example Applications
2 ===================== 2 =====================
3 3
4 users-guide.md - How to build and run JS Mojo applications
5
4 hello.js, world.js - A minimal application that connects to another. 6 hello.js, world.js - A minimal application that connects to another.
5 7
6 wget.js - Uses the network service to load a URL. 8 wget.js - Uses the network service to load a URL.
7 9
8 cube.js - A JS version of examples/sample_app. 10 cube.js - A JS version of examples/sample_app.
9
10 --- Running Mojo Applications ---
11
12 A Mojo application written in JavaScript is launched with mojo_shell like this:
13
14 mojo_shell <js-application-url>
15
16 Where js-application-url is a URL understood by the shell. For example
17 a file or an http URL that names a JS source file. The JS file itself
18 must begin with a Mojo "shebang" that specifies the Mojo URL of the JS
19 content handler. In other words, the first line of the JS source file
20 must be:
21
22 #!mojo:js_content_handler
23
24 Following the shebang should be a single AMD module called "main" whose value
25 is an Application subclass. The JS content handler will create an instance of
26 the Application and make it the client of the Mojo shell. The JS content handler
27 is itself a Mojo application and it's responsible for creating an instance of V8
28 and loading the "main" JS module and all of the modules the main module
29 depends on.
30
31 This is the overall structure of a JS Mojo application:
32
33 ```javascript
34 #!mojo:js_content_handler
35
36 define("main", ["mojo/services/public/js/application",
37 <list of other modules that this application depends on>
38 ],
39 function(appModule, <one parameter per dependent module>) {
40 class MyApplication extends appModule.Application {
41 constructor(appShell, url) {
42 super(appShell, url); // Initializes this.shell, this.url.
43 // MyApplication initializations here.
44 }
45
46 initialize(args) {
47 }
48
49 acceptConnection(url, serviceProvider) {
50 }
51 }
52
53 return MyApplication;
54 });
55 ```
56
57 The hello.js example is little more than this basic skeleton.
58
59 The JS content handler loads the "main" module and makes an instance of its
60 value, which must be an Application subclass. The application's constructor is
61 passed two arguments:
62
63 appShell - a pointer to the Mojo shell. Typically this will be wrapped by a
64 Shell object, see below.
65
66 url - the URL this application was loaded from as a String.
67
68 The (inherited) Application class constructor initializes the shell and url
69 properties. It's unlikely that you'll want to use the appShell argument
70 directly.
71
72 The initialize() and acceptConnection() methods are defined by application.mojom
73 and they're needed because the JS content handler makes the JS application the
74 Mojo shell's client.
75
76
77 --- JavaScript Classes ---
78
79 The JS content handler depends on the ECMAScript6 ("Harmony") classes feature.
80
81
82
83 --- Mojo Application Structure ---
84
85 Mojo applications can connect to services provided by other applications and
86 they can provide services of their own. A service is an implementation of a Mojo
87 interface that was defined as part of a Mojo module in a ".mojom" file.
88
89 To implement a service you'll need the JS "bindings" for the Mojo interface. The
90 bindings are generated by the build system and end up in files whose name is the
91 same as the '.mojom' file with a '.js' suffix. It's often helpful to look at the
92 generated 'mojom.js' files.
93
94 The JS Shell class simplifies connecting to applications and services. It's a
95 wrapper for the Application's appShell argument. The Application constructor
96 creates a Shell and assigns it to |this.shell|.
97
98 The Shell's connectToService() method returns a "proxy" to a service provided by
99 another application.
100
101 The JS bindings for a Mojo interface's API are delivered as a JS module whose
102 name is based on the '.mojom' file's path. For example, to use the Mojo network
103 service you need the JS module based on network_service.mojom:
104
105 ```javascript
106 define("main", [
107 "mojo/services/network/public/interfaces/network_service.mojom",
108 "mojo/services/public/js/application",
109 ]
110 function(netModule, appModule) {
111 class MyApplication extends appModule.Application {
112 initialize(args) {
113 var netService = this.shell.connectToService(
114 "mojo:network_service", netModule.NetworkService);
115 // Use netService's NetworkService methods.
116 }
117 ...
118 }
119
120 return MyApplication;
121 });
122 ```
123
124 The first connectToService() parameter is the Mojo URL for the network service
125 application and the second is the JS "interface" object for NetworkService. The
126 JS interface object's properties identify the (generated) JS bindings classes
127 used to provide or connect to a service. For example (from
128 network_service.mojom.js):
129
130 ```javascript
131 var NetworkService = {
132 name: 'mojo::NetworkService', // Fully qualified Mojo interface name.
133 proxyClass: NetworkServiceProxy,
134 stubClass: NetworkServiceStub,
135 // ...
136 };
137 ```
138
139 The 'proxyClass' is used to access another application's NetworkService and the
140 'stubClass' is used to create an implementation of NetworkService.
141
142 In the netService case above the Shell connects to the Mojo application at
143 "mojo:network_service", then connects to its service called
144 'NetworkService.name' with an instance of 'NetworkService.proxyClass'. The proxy
145 instance is returned. The netService proxy can be used immediately.
146
147
148 --- Mojo Responses are Promises ---
149
150 Mojo functions can return zero or more values called a "response". For example
151 the EchoString function below returns a string or null.
152
153 ```javascript
154 interface EchoService {
155 EchoString(string? value) => (string? value);
156 };
157 ```
158
159 The response is delivered to the function caller asynchronously. In C++ the
160 caller provides a Callback object whose Run() method has one argument for
161 each response parameter. In JS, Mojo functions that specify a response return
162 a Promise object. The Promise resolves to an object with one property per
163 response parameter. In the EchoString case that would be something like
164 {value: "foo"}.
165
166 Similarly, the implementation of a Mojo interface functions that specify a
167 response, must return a Promise. The implementation of EchoString() could
168 be written like this:
169
170 ```javascript
171 MyEchoStringImpl.prototype.EchoString = function(s) {
172 return Promise.resolve({value: s});
173 };
174 ```
175
176 - Applications can request and provide services
177
178 When an application starts, its initialize() method runs and then its
179 acceptConnection() method runs. The acceptConnection() method
180 indicates that another application has connected to this one and it
181 always runs at least once.
182
183 ```javascript
184 acceptConnection(initiatorURL, serviceProvider) {
185 // provide services to the initiator here
186 // request services from the initiator here
187 }
188 ```
189
190 The acceptConnection serviceProvider argument can be used to provide
191 services to the initiator, and to request services from the
192 initiator. An application can decide exactly what to do based on the
193 initiator's URL. The serviceProvider argument is-a JS ServiceProvider,
194 an object that wraps a Mojo ServiceProvider proxy.
195
196 The ServiceProvider requestService() method gets a proxy for a service
197 from the initator and optionally provides a client implementation.
198
199 The ServiceProvider provideService() method registers an interface
200 implementation factory for a Mojo interface. The factory function is
201 provided with an proxy for the interface's client, if it has one.
202
203 An application can also connect to other applications and their
204 services using its shell's connectToApplication() and
205 connectToService() methods. The shell's connectToApplication() returns
206 a ServiceProvider. The shell's connectToService() method is just a
207 convenience, it's defined like this:
208
209 ```javascript
210 connectToService(url, service, client) {
211 return this.connectToApplication(url).requestService(service, clientImpl);
212 };
213 ```
214
215 The value of service is an interface object that identifies a Mojo
216 interface that the application at url implements.
217
218 The usage examples that follow are based on the following trivial Mojo
219 interface:
220
221 ```javascript
222 interface EchoService {
223 EchoString(string? value) => (string? value);
224 };
225 ```
226
227 -- Requesting a service using the Application's Shell
228
229 Given the URL of a Mojo application that implements the EchoService we
230 can use the application's shell to get an EchoService proxy. Here's a
231 complete application:
232
233 ```javascript
234 #!mojo:js_content_handler
235
236 define("main", [
237 "console",
238 "mojo/services/public/js/application",
239 "services/js/test/echo_service.mojom"
240 ], function(console, appModule, echoModule) {
241
242 class EchoShellRequest extends appModule.Application {
243 initialize(args) {
244 var url = "file:/foo/bar/echo.js";
245 var echoService = this.shell.connectToService(url, echoModule.EchoService) ;
246 echoService.echoString("foo").then(function(result) {
247 console.log("echoString(foo) => " + result.value);
248 });
249 }
250 }
251 return EchoShellRequest;
252 });
253 ```
254
255
256 -- Providing a service
257
258 A complete application that unconditionally provides the EchoService
259 looks like this:
260
261 ```javascript
262 #!mojo:js_content_handler
263
264 define("main", [
265 "mojo/services/public/js/application",
266 "services/js/test/echo_service.mojom"
267 ], function(appModule, echoModule) {
268
269 class EchoService extends appModule.Application {
270 acceptConnection(initiatorURL, serviceProvider) {
271 function EchoServiceImpl(client) {
272 this.echoString = function(s) {
273 return Promise.resolve({value: s});
274 };
275 }
276 serviceProvider.provideService(echoModule.EchoService, EchoServiceImpl);
277 }
278 }
279 return EchoService;
280 });
281 ```
282
283 As you can see, EchoServiceImpl is just a function that returns an
284 object that implements the methods in the Mojo EchoService
285 interface. If the EchoService defined a client interface, the factory
286 function's client parameter would be a proxy for the initiator's
287 client service. EchoService doesn't have a client so we could have
288 omitted this parameter.
289
290 Each time another application connects to this one, the EchoServiceImpl
291 function will be called. The caller will be able to run the
292 echoString() method and will get its response via a Promise.
293
294
295 -- Final note
296
297 An initiator's serviceProvider object can be retained and used to
298 request or provide services at any time, not just from within
299 application's acceptConnection() method.
300
301
302 --- Interface Parameters ---
303
304 The caller and callee use cases that follow are in terms of the following mojom :
305
306 ```
307 [Client=Bar]
308 interface Foo {
309 }
310
311 [Client=Foo] // Redundant but always implicitly true.
312 interface Bar {
313 }
314
315 interface I {
316 provideFoo(Foo foo);
317 requestFoo(Foo& foo); // effectively: provideFoo(Bar bar)
318 }
319 ```
320
321 -- In General
322
323 From a user's point of view, the bindings are in terms of the (remote)
324 proxy class and the (local) stub class's implementation delegate
325 (internally, that's the stub class's delegate$ property). The
326 bindings will add/use a local$ property on proxy objects which points
327 to the stub class's implementation delegate. They also manage remote$
328 property on the implementation delegate whose value is the proxy.
329
330 All that implies:
331
332 fooImpl.remote$.local$ == fooImpl (the stub class's delegate)
333 fooProxy.local$.remote$ == fooProxy
334
335
336 -- Callers
337
338 Assuming that we have a proxy for interface I, iProxy.
339
340 An iProxy.provideFoo() call implies that we have an implementation of
341 Foo, and want a proxy for Bar (Foo's client).
342
343 ```javascript
344 var myFooImpl;
345 provideFoo(myFooImpl);
346 myFooImpl.remote$; // A Bar proxy initialized by provideFoo(), undefined if Foo has no client.
347 ```
348
349 An iProxy.requestFoo() call implies that we have an implementation of
350 Bar and want a proxy for Foo (Bar's client).
351
352 ```javascript
353 var myBarImpl; // If Foo has no client then this is just {}.
354 requestFoo(myBarImpl);
355 myBarImpl.remote$; // A Foo proxy initialized by requestFoo.
356 ```
357
358 The wget.js example includes a request for the URLLoader service.
359
360 -- Callees
361
362 An implementation of provideFoo(Foo foo) implies that we have an
363 implementation of Bar (Foo's client) and want a proxy to the Foo
364 that has been passed to us.
365
366 ```javascript
367 void provideFoo(fooProxy) {
368 fooProxy.local$ = myBarImpl; // sets myFooImpl.remote$ = fooProxy
369 }
370 ```
371
372 An implementation of requestFoo(Foo& foo) implies that we have an
373 implementation of Foo and want a proxy for the Bar (Foo's client)
374 that's been passed to us.
375
376 ```javascript
377 void requestFoo(barProxy) {
378 barProxy.local$ = myFooImpl; // sets myFooImpl.remote$ = barProxy
379 }
380 ```
381
OLDNEW
« no previous file with comments | « no previous file | examples/js/users-guide.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698