I want to extend Promise
and change the then
signature so its callback receives two values. I tried different approaches two of which are documented and tested here. Sadly, I get various errors or the resulting class does not behave like a Promise.
Approach 1: Wrapping a native Promise
export class MyWrappedPromise {
constructor(data) {
this.data = data;
this.promise = new Promise(evaluate.bind(data));
}
then(callback) {
this.promise.then(() => callback(this.data, ADDITIONAL_DATA));
}
catch(callback) {
this.promise.catch(callback);
}
}
Approach 2: Extending native Promises
export class MyExtendedPromise extends Promise {
constructor(executor, data) {
super(executor);
this.data = data;
}
static create(data) {
return new MyExtendedPromise(evaluate.bind(data), data);
}
then(callback) {
return super.then(() => callback(this.data, ADDITIONAL_DATA));
}
}
Does anyone have any suggestion on what I am doing wrong? Feel free to create a PR on GitHub.
thanks
------------------- Edit ---------------------
Some Additional code and info to make the code above more understandable without looking at the code and tests on Github.
evaluate
is just the Promise executor function. I extracted it out so I can keep it consistent across all my implementations and tests. It may look convoluted but it's structured that way to simulate my "real" project.
export function evaluate(resolve, reject) {
const data = this;
function getPromise(data) {
return !!data ? Promise.resolve(data) : Promise.reject(new Error("Error"));
}
getPromise(data)
.then(resolve)
.catch(reject);
}
ADDITIONAL_DATA is just a string to simulate the second value in the callback. It's also extracted to be consistent across all versions and tests.
------------------- Edit 2---------------------
Errors that come up depending on the solution
catch
is not accessibleUnhandledPromiseRejectionWarning:
warnings because errors/rejects are not getting propagated up correctly.rejects
checks in my test suitesYou have problems (especially with unhandled rejections) because you are not implementing the then
interface correctly. Remember that .catch(onRejected)
is just an alias for .then(undefined, onRejected)
, and then
with two parameters is the actual core method of every promise.
You were always ignoring the second argument, so no rejection ever got handled. You need to write
then(onFulfilled, onRejected) {
return super.then(res => onFulfilled(res, this.ADDITIONAL_DATA), onRejected);
// or `this.promise.then` instead of `super.then`
}
I don't understand very well why you do have a factory method, instead of using directly the constructor.
Do you mean something like this?
class MyExtendedPromise extends Promise {
constructor(executor, data) {
super(executor);
this.data = data;
}
then(callback, test) {
console.log('passed new parameter in then:', test);
console.log('additional data:', this.data);
return super.then(data => callback(data, test));
}
}
new MyExtendedPromise((resolve, reject) => {
setTimeout(() => resolve(true), 2000);
}, 'other additional data').then(data => console.log('my then', data), 'hello world');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With