How come resolving a settled Promise doesn't throw?
On Tue, Feb 28, 2017 at 10:12 AM, /#!/JoePea <joe at trusktr.io> wrote:
f.e.
let resolve let p = new Promise(r => resolve = r) resolve(5) // resolves the promise. resolve(4) // noop (in Chrome), but why not throw an error?
I only tested in Chrome, and I'm assuming it follows spec, but I could be wrong.
I'm asking because it seems that throwing an error will prevent shots in the foot, so that code doesn't assume that resolving on an already resolved Promise worked, although it didn't. It seems like it can lead to unexpected failures.
That's correct behavior, yes. In general, it's because the internal state of a promise is meant to be unobservable unless you're specifically listening to it.
Also, making promise resolution idempotent makes dealing with things way easier. Similarly, most deferred libraries ensure their resolution is idempotent.
That seems like it would allow synchronous observation of Promise state - consider:
function isResolved(promise) {
try {
new Promise((resolve) => {
resolve(promise);
resolve();
});
} catch (e) {
return true;
}
return false;
}
Although now that I think about it, it wouldn't have to care about the
promise state, resolve
and reject
could just throw if they're invoked
more than once.
BTW, there's still usefulness of making resolution/rejection idempotent and never throwing. IMHO, I'd just like to see this die.
Isiah Meadows me at isiahmeadows.com
Throwing on already resolved/rejected will break the Web 'cause the following example pattern is quite common.
class Lie extends Promise {
constructor(fn) {
let _resolve, _reject;
super((resolve, reject) => fn(
_resolve = resolve,
_reject = reject
));
this._resolve = _resolve;
this._reject = _reject;
}
reject(error) {
this. _reject(error);
return this;
}
resolve(how) {
this._resolve(how);
return this;
}
cancel(...reason) {
this._reject(...reason);
return this;
}
}
// resolve in 5 seconds with 123
const p = new Lie((res, rej) => setTimeout(res, 5000, 'timeout'));
// however, something else could happen before / or after
setTimeout(() => p.resolve('hello there').then(console.log), 1000);
As summary, after years without throwing, I don't see why it should now.
f.e.
let resolve let p = new Promise(r => resolve = r) resolve(5) // resolves the promise. resolve(4) // noop (in Chrome), but why not throw an error?
I only tested in Chrome, and I'm assuming it follows spec, but I could be wrong.
I'm asking because it seems that throwing an error will prevent shots in the foot, so that code doesn't assume that resolving on an already resolved Promise worked, although it didn't. It seems like it can lead to unexpected failures.