Philip Frank created THRIFT-4406:
------------------------------------

             Summary: JavaScript: Use modern Promise implementations
                 Key: THRIFT-4406
                 URL: https://issues.apache.org/jira/browse/THRIFT-4406
             Project: Thrift
          Issue Type: Improvement
          Components: JavaScript - Compiler
            Reporter: Philip Frank
            Priority: Minor


I would like to acces the results of service method invocations in a web 
browser environment using 
[Promises|https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this]
 (or a compatible API). I'm willing to work on the necessary changes in the 
compiler and am seeking guidance regarding the best way to make these changes.

Current state:

In browser JS, i can pass a callback function as last argument when calling a 
method:

{code:javascript}
    service.getFoo('a1', 'a2', function(foo) {
        alert(foo);
    });
{code}


There is also a synchronous API, however this blocking way is discouraged by 
browser vendors. It also fails with an error for me when using 
WebSocketTransport instead of XHRTransport.

{code:javascript}
    alert(service.getFoo('a1', 'a2'));
{code}

In JS code generated for NodeJS, the 'q' library is included, which provides an 
API mostly compatible with JavaScript's native Promises.

{code:javascript}
    service.getFoo('a1', 'a2').then(function(foo) {
        alert(foo);
    });
{code}

>From what I can tell 'q' is mostly irrelevant today since native Promises are 
>supported in NodeJs [for many 
>versions|http://node.green/#ES2015-built-ins-Promise].

Regarding support in browsers, native Promises work in [recent versions of most 
browsers|https://caniuse.com/#feat=promises] and can be enabled in other cases 
by including one of the many polyfill libraries, like the popular 
[core-js|https://github.com/zloirock/core-js#ecmascript-6-promise].


Proposed solution:

In both browser and nodeJS, service methods return a Promise when invoked 
without a callback. This has many advantages for developers:
* Promise API is an established standard in modern JavaScript (ECMAScript), it 
is easy for developers to consume and to use with other libraries
* Error handling is possible through {{catch()}}
* Result handling is very flexible through chaining
* Promises can be combined through {{Promise.all()}} and {{Promise.race()}}
* The 
[{{await}}|https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await]
 keyword makes it even easier to write async code. (Support limited to some 
browsers or with cross-compilers like [babel|https://babeljs.io/])


However, this would break compatibility:
* Synchronous (blocking) invocations would no longer be supported, instead a 
Promise instead of the value is returned
* with NodeJS code relying on some features specific to 'q' (e.g. {{finally()}} 
and {{done()`)
* Internet Explorer needs a polyfill for Promises


I'm assuming the code generated by Thrift should stay backwards compatible in 
the foreseeable future, so I suggest making these changes behind a new compiler 
flag, {{-gen js:es6}} (for ECMAScript 6). This would also open up the ability 
to leverage more ES6 features in the future: For example, using {{const}} 
instead of {{var}} might give a slight performance improvement and using the 
{{class}} syntax could improve readability of the generated code.

Please share any thoughts regarding this topic or hints towards a good 
implementation. If there are no objections, I'm willing to start working on 
this soon, with the hopes of getting my changes accepted into the project 
codebase.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

Reply via email to