patternjavascriptMinor
Promise.jsm demo of Promise.all and Promise.defer
Viewed 0 times
alldeferpromiseandjsmdemo
Problem
I created this demo example for MDN documentation to show how to use
People are recommending I avoid
The code downloads images from an array and after all images are downloaded it completes the main
```
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
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:
Additional notes:
-
Don't do
-
I'd avoid using
-
Name your variables and functions properly and verbosely.
// 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.