Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

User talk:Poltawski/Javascript promises: Difference between revisions

From MoodleDocs
Line 3: Line 3:




Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). In order to make best use of promises in Moodle more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].


=== Summary ===
=== Always return or throw  ===
<blockquote>
 
What can we do here? There are three things:
When writing promises they must:
* return another promise
* return another promise, or
* return a synchronous value (or undefined)
* return a synchronous value (or undefined), or
* throw a synchronous error
* throw a synchronous error
</blockquote>


=== Always return or throw  ===
Good:
<code>
// Good:
str.get_strings(stringRequests).then(function(title) {
    return templates.renderPix(image, 'core', title);
}).then(function(pixhtml) {
    $('#selector').html(pixhtml);
    makeUIVisible();
    return;
});


Always return in promises. Seee https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html #5


// Bad:
str.get_strings(stringRequests).then(function(title) {
    templates.renderPix(image, 'core', title).function(pixhtml) {
$('#selector').html(pixhtml);
});
}).then(function() {
    // Wrong because renderPix() has not guaranted to be resolved here.
    makeUIVisible();
});
</code>


=== Do not nest ===
=== Do not nest ===


The great advantage of promises is keeping async code linear rather than nested in <i>callback hell</i> and handling errors in one place, by nesting promises these advantages are lost.
The great advantage of promises is keeping async code linear rather than nested in <i>callback hell</i> and handling errors in one place, by nesting promises these advantages are lost.
<code>
// GOOD:
renderPromise().then(function (html) {
return Str.get_string('competencypicker', 'tool_lp');
}).then(function(title) {
self._popup = new Dialogue(title, html);
});
// BAD:
return renderPromise().then(function (html) {
return Str.get_string('competencypicker', 'tool_lp').then(function(title) {
self._popup = new Dialogue(title, html);
});
});
</code>

Revision as of 13:35, 12 June 2017

Promises

Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article we have a problem with promises). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by eslint-plugin-promise.

Always return or throw

When writing promises they must:

  • return another promise, or
  • return a synchronous value (or undefined), or
  • throw a synchronous error

Good: // Good: str.get_strings(stringRequests).then(function(title) {

   return templates.renderPix(image, 'core', title);

}).then(function(pixhtml) {

   $('#selector').html(pixhtml);
   makeUIVisible();
   return;

});


// Bad: str.get_strings(stringRequests).then(function(title) {

   templates.renderPix(image, 'core', title).function(pixhtml) {

$('#selector').html(pixhtml); }); }).then(function() {

   // Wrong because renderPix() has not guaranted to be resolved here.
   makeUIVisible();

});

Do not nest

The great advantage of promises is keeping async code linear rather than nested in callback hell and handling errors in one place, by nesting promises these advantages are lost.

// GOOD: renderPromise().then(function (html) { return Str.get_string('competencypicker', 'tool_lp'); }).then(function(title) { self._popup = new Dialogue(title, html); });


// BAD: return renderPromise().then(function (html) { return Str.get_string('competencypicker', 'tool_lp').then(function(title) { self._popup = new Dialogue(title, html); }); });