Asynchronous Method Dispatch (AMD) in JavaScript
JavaScript is single-threaded, therefore it is very important to consider how servant implementation decisions affect the overall application. In a JavaScript program with a graphical user interface, spending too much time in the implementation of a Slice operation can delay the processing of UI events and adversely impact the user experience.
Asynchronous Method Dispatch (AMD), the server-side equivalent of AMI, allows a server to receive a request but then suspend its processing. When processing resumes and the results are available, the server sends a response explicitly using a callback object provided by the Ice run time.
AMD is transparent to the client, that is, there is no way for a client to distinguish a request that, in the server, is processed synchronously from a request that is processed asynchronously.
One use case that requires AMD is nested invocations. Since all outgoing invocations have asynchronous semantics, an operation implementation whose results depend on the outcome of a nested invocation must postpone its response until the nested invocation completes.
On this page:
Using AMD in JavaScript
To use asynchronous dispatch, the operation implementation must return a promise object.
The implementation can return an instance of the standard Promise
type or any other type that provides a then
method.
For example, suppose we define the following operation:
interface I { int foo(short s, out long l); }
The servant method for operation foo
should have this signature:
foo(s, current) { ... }
foo(s:string, current:Ice.Current):PromiseLike<[number, Ice.Long]> { ... }
It should return a promise object that, when fulfilled, returns an array containing an integer and a long.
AMD Exceptions in JavaScript
There are two processing contexts in which the logical implementation of an AMD operation may need to report an exception: the dispatch context (the call sequence that invokes the servant method), and the context of the promise (the call sequence that rejects the promise).
These are not necessarily two different contexts: it is legal to return a rejected promise from the dispatch context.
It is legal for the implementation to raise an exception instead of returning a rejected promise.
AMD Example in JavaScript
To demonstrate the use of AMD in Ice, consider an operation that must make a nested invocation:
module Demo { exception RequestFailed { string reason; } interface TaxManager { float computeTax(float amount) throws RequestFailed; } interface ShoppingCart { float computeTotal() throws RequestFailed; } }
In this over-simplified example, a shopping cart object must query a tax manager object in order to compute the total amount owed by the customer.
Our servant class derives from Demo.ShoppingCart
and supplies a definition for the computeTotal
method:
class ShoppingCartI extends Demo.ShoppingCart { constructor() { this._subtotal = 0.0; } computeTotal(current) { const taxManager = ... // get TaxManager proxy const subtotal = this._subtotal; return taxManager.computeTax(subtotal).then( tax => subtotal + tax; ex => { if(ex instanceof Demo.RequestFailed) { throw ex; // Relay RequestFailed exception from computeTax } else { throw new Demo.RequestFailed("failed: " + ex.toString()); } }); } }
class ShoppingCartI extends Demo.ShoppingCart { constructor() { this._subtotal = 0.0; } computeTotal(current:Ice.Current):PromiseLike<number> { const taxManager = ... // get TaxManager proxy const subtotal = this._subtotal; return taxManager.computeTax(subtotal).then( tax => subtotal + tax; ex => { if(ex instanceof Demo.RequestFailed) { throw ex; // Relay RequestFailed exception from computeTax } else { throw new Demo.RequestFailed("failed: " + ex.toString()); } }); } _subtotal:number; }
The implementation of computeTotal
makes a nested invocation of computeTax and returns a promise whose
resolve and reject functions return the result of the computeTotal
dispatch.