Attaching an Attribute to a Promise
Another question on SO sparked my interest in creating setTimeout
that returned Promise and timerId, but would not break backwards compatibility. This is the question I mean.
It just asks if the inner return statement in the method is _.delay
underscore.js
extraneous or serves a purpose. Here's a block of code.
This is the code for _.delay:
// Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function() { // this is to return the timerId
return func.apply(null, args); // this guy right is in question
}, wait);
};
Given that setTimeout does not currently return a Promise, I came up with an idea of โโwhat is possible for future validation if setTimeout returns a promise one day.
This setTimeout
requires the timerId to be returned so that it can be canceled. Therefore, in order to return a Promise
, you will need to bind timerId to a Promise in order to return a Promise and access the timer.
Then you can change clearTimeout
to do the same as now when the timerId is set, but for the Promise, it uses the Promise.timerId to clear the timeout and cancel the Promise. Of course, you will also need to refuse to cancel promises ...
Anyway ... I started working on something for fun and came across something I couldn't explain. If you run the snippet below, you can see that the promise has an attribute .timerId
before it is returned, but the attribute is missing after returning. Can anyone explain this?
function pseudoSetTimeout( func, wait ) {
let timerId,
promise = new Promise( ( resolve, reject ) => {
timerId = setTimeout( () => {
let returnVal = func();
resolve( returnVal );
}, wait );
});
promise.timerId = timerId;
console.log( "promise before return: ", promise );
return promise;
}
function callback() {
return "Callback fired";
}
let timeout = pseudoSetTimeout( callback, 1000 )
.then( ( val ) => {
console.log( val );
});
console.log( "returned promise: ", timeout );
source to share
then
in:
pseudoSetTimeout( callback, 1000 )
.then( ( val ) => {
console.log( val );
});
returns a new promise that does not return pseudoSetTimeout
. This is a promise with undefined
the promised value as the callback then
does not return anything.
You can get it to work without applying then
at assignment time:
function pseudoSetTimeout( func, wait ) {
let timerId,
promise = new Promise( ( resolve, reject ) => {
timerId = setTimeout( () => {
let returnVal = func();
resolve( returnVal );
}, wait );
});
promise.timerId = timerId;
console.log( "promise before return: ", promise );
return promise;
}
function callback() {
return "Callback fired";
}
let timeout = pseudoSetTimeout( callback, 1000 );
timeout.then( ( val ) => {
console.log( val );
});
console.log( "returned promise: ", timeout );
Since it then
is critical when using promises and is often used to chain them, it seems like the idea of โโattaching a custom property to a promise loses its usefulness.
source to share
A really interesting question.
Not sure how it's done inside node, but looking at the bluebird code, there is any indication: https://github.com/petkaantonov/bluebird/blob/master/src/thenables.js
My guess would be that the promise returned is actually a different object.
source to share
Due to the reasons mentioned in other answers, I would return a "tuple" instead of using the property as promised:
function pseudoSetTimeout( func, wait ) {
let timerId,
promise = new Promise( ( resolve, reject ) => {
timerId = setTimeout( () => {
let returnVal = func();
resolve( returnVal );
}, wait );
});
let result = [timerId, promise];
console.log ( "returning: ", result );
return result;
}
function callback() {
return "Callback fired";
}
let [timeout, promise] = pseudoSetTimeout( callback, 1000 );
promise.then( ( val ) => {
console.log( val );
});
console.log( "returned timeout: ", timeout );
source to share