Regarding var
vs. let
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?
Regarding your comment: "People"'s opinion on var
vs. let
is a bit off... It makes sense for the web not to use let
just yet as not all browsers support let
.
But within the mozilla code base let is actually already used since years and pretty stable. There are more than 83.000 let
s in mozilla-central (via ag -w let | wc -l
). Brendan Eich (I think) coined the term "let is the new var" (for mozilla-specific code) way back when JS1.7 was released a part of Firefox 2 in 2006. Ever since, it has seen wide-spread adoption within the mozilla code base and add-ons alike.
But, since you're writing documentation, it would be better to follow the lead of the main MDN contributors, even if you write mozilla-specific examples aimed at platform and add-on developers. I'm not sure what the MDN policy is on this...
I wrote a bunch of mozilla-specific examples in the past for MDN, and used let
and other stuff like generators, and never was told to stop that. But maybe I just wasn't caught.
Replacing one with the other
You asked about this in a comment, but I think it would be more appropriate to answer here.
In general you can replace var
with let
in most cases, except where you really want the hoisting rules. E.g. one example where stuff would break.
try {
var name = getName();
} catch (ex) { ... }
console.log(name);
But with let
, name
will be only valid within the try-block.
try {
let name = getName();
} catch (ex) { ... }
console.log(name); // Either undefined or an error, depending on strict-mode.
You could still write this as (and I guess it would have been a good idea to write it like this in the first place, even with var
).
let name;
try {
name = getName();
} catch (ex) { ... }
console.log(name); // Either undefined or an error, depending on strict-mode.
The other way round is more tricky. Don't do it blindly. Be aware of name clashes it may create due to different scoping/hoisting rules, and what scoping difference means for "global" code in particular.
A problematic example:
for (var i = 0; i < 10; ++i) {
let p = i * 10;
setTimeout(function() { console.log(p) });
}
// 0, 10, 20, 30, 40, 50, 60, 70, 80, 90
Using var p
is wildly different because p
gets hoisted outside of the loop block while let p
is hoisted within the block (JS1.7) or not-really-hoisted-but-kinda (ES6):
for (var i = 0; i < 10; ++i) {
var p = i * 10;
setTimeout(function() { console.log(p) });
}
// 90, 90, 90, 90, 90, 90, 90, 90, 90, 90
JS1.7 to ES6 differences.
The hoisting difference of let
is the most important practical difference between JS1.7 and ES6 let
.
(function() { console.log(i); let i = 0; })();
This will log undefined
in JS1.7, but should throw an error in ES6 because i
was referenced before it actually was declared.
Since you should avoid to write such code anyway, it shouldn't really make much difference in practice, except to expose the occasional bug once the engine switches from JS1.7 to ES6 behavior.
There are some other differences (e.g. no more let-blocks), but I'd consider them extremely minor in practice and don't think these differences would affect lots of production code.
Regarding Promise.jsm
documentation and your code.
Well, I don't really think the example is appropriate:
- It relies on the network.
- It relies on some external resources, which may get removed in the future at any point.
- It isn't simple enough.
- It is incorrect when put into a strict-mode function.
If write an example like this, keeping it as simple as possible.
Components.utils.import('resource://gre/modules/Promise.jsm');
/**
* Example function, just returning a promise that
* will resolve or reject after a timeout.
*/
function createTimeoutPromise(shouldSucceed, timeout) {
var p = Promise.defer();
setTimeout(function () {
if (shouldSucceed) {
p.resolve(timeout);
}
else {
p.reject(timeout);
}
}, timeout);
return p.promise;
}
/**
* Success case.
*/
(function() {
var promises = [];
for (var i = 0; i < 10; ++i) {
promises.push(createTimeoutPromise(true, i * 100));
}
var combined = Promise.all(promises);
combined.then(
function onResolved(result) {
console.log('resolved', result);
},
function onRejected(result) {
console.log('rejected', result);
});
// Since all promises eventually resolve/succeed, onResolved will be called.
// Promise.all will pass an array of all resolve() results.
// This hence logs:
// "resolved" Array [ 0, 100, 200, 300, 400, 500, 600, 700, 800, 900 ]
})();
/**
* Failure case.
*/
(function() {
var promises = [];
for (var i = 0; i < 10; ++i) {
// Odd numbered promises should fail: i % 2 == 0
promises.push(createTimeoutPromise(i % 2 == 0, i * 100));
}
var combined = Promise.all(promises);
combined.then(
function onResolved(result) {
console.log('resolved', result);
},
function onRejected(result) {
console.log('rejected', result);
});
// Since odd numbered promises will be rejected/fail, onRejected will be called.
// Promise.all will immediately reject the returned combined promise once the
// first sub-promise fails, i.e. promise "100".
// Other resolved and rejected promises won't be passed.
// This hence logs
// "rejected" 100
})();
I'm not quite sure how much of a point there is maintaining Promise.jsm
documentation, since ES6 Promise
s landed in the meantime. I'd expect that Promise.jsm
will get phased out at some point.