The reasoning is simple but not necessarily self evident.
.then()
returns a promise
- if
then
is called on a subclass of Promise, the returned promise is an instance of the subclass, not Promise itself.
- the
then
returned promise is constructed by calling the subclass constructor, and passing it an internal executor function that records the value of resolve
and reject
arguments passed to it for later use.
- "later use" covers resolving or rejecting the promise returned by
then
asynchronously when monitoring execution of onfulfilled
or onrejected
handlers (later) to see if they return a value (which resolves the then
returned promise) or throw an error (which rejects the promise).
In short then
calls internally obtain and record references to the resolve
and reject
functions of promises they return.
So regarding the question,
new MyPromise( 'p1')
works fine and is the first call to the subclass constructor.
.then( someFunction)
records someFunction
in a list of then
calls made on new MyPromise
(recall then
can be called multiple times) and attempts to create a return promise by calling
new MyPromise( (resolve, reject) => ... /* store resolve reject references */
This is the second call to the subclass constructor coming from then
code. The constructor is expected to (and does) return synchronously.
On return from creating the promise to return, the .then
method makes an integrity check to see if the resolve
and reject
functions it needs for later use are in fact functions. They should have been stored (in a list) along with callbacks provided in the then
call.
In the case of MyPromise
they are not. The executor passed by then
, to MyPromise
, is not even called. So then
method code throws a type error "Promise resolve or reject function is not callable" - it has no means of resolving or rejecting the promise it is supposed to return.
When creating a subclass of Promise, the subclass constructor must take an executor function as its first argument, and call the executor with real resolve
and reject
functional arguments. This is internally required by then
method code.
Doing something intricate with MyPromise
, perhaps checking the first parameter to see if it is a function and calling it as an executor if it is, may be feasible but is outside the scope of this answer! For the code shown, writing a factory/library function may be simpler:
function namedDelay(name, delay=1000, value=1) {
var promise = new Promise( (resolve,reject) => {
setTimeout(() => {
resolve(value)
}, delay)
}
);
promise.name = name;
return promise;
}
namedDelay( 'p1')
.then(result => {
console.log('fulfilled, result: ', result)
})
.catch(err => {
console.error('err: ', err)
})
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…