HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Promise.jsm demo of Promise.all and Promise.defer

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
alldeferpromiseandjsmdemo

Problem

I created this demo example for MDN documentation to show how to use Promise.all and Promise.defer in user created promise. I used lets because I thought if I didn't it would mess it up.

People are recommending I avoid let because the standard is not there yet and it looks like when it lands it will be a little different. Can you please advise?

The code downloads images from an array and after all images are downloaded it completes the main promise.

```
Components.utils.import("resource://gre/modules/Promise.jsm");

var myPromise = myUserDefinedPromise();
myPromise.then(
function(aSuccessReason) {
alert('myPromise was SUCCESFUL and reason was = "' + aSuccessReason + '"');
},
function(aRejectReason) {
alert('myPromise FAILED for reason = "' + uneval(aRejectReason) + '"');
}
);

function myUserDefinedPromise() {
try {
var mySubPromises = [];

var imagePaths = ['http://www.mozilla.org/media/img/firefox/favicon.png', 'https://developer.cdn.mozilla.net/media/redesign/img/favicon32.png'];
[].forEach.call(imagePaths, function(path) {
let myImage = new Image();
let loadThisImagePromise = Promise.defer();
mySubPromises.push(loadThisImagePromise.promise);
myImage.onload = function() {
loadThisImagePromise.resolve('Succesfully loaded image at path = "' + path + '" the width of this image is = "' + this.naturalWidth + '".');
if (!this.naturalWidth) {
loadThisImagePromise.reject('Image loaded but it has 0 width at path = "' + path + '" the naturalWidth was 0');
}
}
myImage.onerror = function(e) {
loadThisImagePromise.reject('An error occured while loading path = "' + path + '". The error = ' + uneval(e));
}
myImage.onabort = function(e) {
loadThisImagePromise.reject('Image load was aborted loading path = "' + path + '".');
}
myImage.src = path;
});

return Promise.all(mySubPromises);
} catch(ex) {
return Promise.r

Solution

Here's my implementation:

// So we define a function that loads images, and returns a promise for us to listen to
function loadImages(images){

  // We can take advantage of `map` which iterates through an array and makes an array
  // out of the returns of each iteration. In this case, we return a promise for each
  // url, for `Promise.all` to listen to later.
  var promises = images.map(function(url){

    // Create a Deferred object and image, and handle the resolution stuff.
    var deferred = Promise.defer();
    var image = new Image();
    image.onload = function(){deferred.resolve('image success: '+ url);};
    image.onerror = function(){deferred.reject('image failed: ' + url);};
    image.onerror = function(){deferred.reject('image aborted: ' + url);};
    image.src = url;

    // Return the promise, which will be stored in the array, thanks to `map`
    return deferred;
  });

  // Listen on the array of promises (aha moment: jQuery.when == Promises.all, more or less.)
  return Promise.all(promises);
}

// Now we use `loadImages`, loading an array of urls, and listening for notices
loadImages([
  'http://www.mozilla.org/media/img/firefox/favicon.png',
  'https://developer.cdn.mozilla.net/media/redesign/img/favicon32.png'
]).then(function(value){
  console.log('loadImages successful: ' + value);
},function(error){
  console.log('loadImages failed: ' + error);
});


Additional notes:

-
Don't do [].forEach.call. Aside from looking very hackish, it creates an unnecessary array. Do Array.prototype.forEach.call instead.

-
I'd avoid using try-catch. While it's a good measure for errors, it's bad for optimization. Some optimizing compilers (I think V8) can't optimize code inside try-catch.

-
Name your variables and functions properly and verbosely.

Code Snippets

// So we define a function that loads images, and returns a promise for us to listen to
function loadImages(images){

  // We can take advantage of `map` which iterates through an array and makes an array
  // out of the returns of each iteration. In this case, we return a promise for each
  // url, for `Promise.all` to listen to later.
  var promises = images.map(function(url){

    // Create a Deferred object and image, and handle the resolution stuff.
    var deferred = Promise.defer();
    var image = new Image();
    image.onload = function(){deferred.resolve('image success: '+ url);};
    image.onerror = function(){deferred.reject('image failed: ' + url);};
    image.onerror = function(){deferred.reject('image aborted: ' + url);};
    image.src = url;

    // Return the promise, which will be stored in the array, thanks to `map`
    return deferred;
  });

  // Listen on the array of promises (aha moment: jQuery.when == Promises.all, more or less.)
  return Promise.all(promises);
}

// Now we use `loadImages`, loading an array of urls, and listening for notices
loadImages([
  'http://www.mozilla.org/media/img/firefox/favicon.png',
  'https://developer.cdn.mozilla.net/media/redesign/img/favicon32.png'
]).then(function(value){
  console.log('loadImages successful: ' + value);
},function(error){
  console.log('loadImages failed: ' + error);
});

Context

StackExchange Code Review Q#56822, answer score: 3

Revisions (0)

No revisions yet.