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
No edit summary
Line 12: Line 12:
* throw a synchronous error
* throw a synchronous error


Good:
==== Correct ====
<code>
<code javascript>
// Good:
// Good:
str.get_strings(stringRequests).then(function(title) {
str.get_strings(stringRequests).then(function(title) {
Line 22: Line 22:
     return;
     return;
});
});
</code>


 
==== Incorrect ====
// Bad:
<code javascript>
str.get_strings(stringRequests).then(function(title) {
str.get_strings(stringRequests).then(function(title) {
     templates.renderPix(image, 'core', title).function(pixhtml) {
     templates.renderPix(image, 'core', title).function(pixhtml) {
Line 39: Line 40:
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>
==== Correct ====
 
<code javascript>
// GOOD:
renderPromise().then(function (html) {
renderPromise().then(function (html) {
return Str.get_string('competencypicker', 'tool_lp');
return Str.get_string('competencypicker', 'tool_lp');
Line 47: Line 47:
self._popup = new Dialogue(title, html);
self._popup = new Dialogue(title, html);
});
});
</code>


==== Incorrect ====


// BAD:
<code javascript>
return renderPromise().then(function (html) {
return renderPromise().then(function (html) {
return Str.get_string('competencypicker', 'tool_lp').then(function(title) {
return Str.get_string('competencypicker', 'tool_lp').then(function(title) {

Revision as of 13:37, 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

Correct

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

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

}).then(function(pixhtml) {

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

});

Incorrect

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.

Correct

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

Incorrect

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