最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Attaching an attribute to a Promise - Stack Overflow

programmeradmin2浏览0评论

Another question on SO perked my interest in creating a setTimeout that returned a Promise and a timerId, yet would not break backwards patibility. This is the question I am referring to.

It simply asks if the inner return statement in the _.delay method of underscore.js is extraneous or serves a purpose. Here is the 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);
};

Considering setTimeout does not currently return a Promise, I proposed the idea that it is possibly there for future proofing, incase setTimeout does one day return a promise.

To do this setTimeout would need to return a timerId so that it can be canceled. So to return a Promise you would need to attach the timerId to the Promise, so that the Promise is returned and the timerId is accessable.

You could then modify clearTimeout to perform exactly how it does now when given a timerId, but for a Promise it uses Promise.timerId to clear the timeout and cancel the Promise. Of course Promise canceling would need to be implemented as well...

Anyhow... I started working on something for fun and came across something I haven't been able to explain. If you run the snippet below, you will see that the promise has .timerId attribute before it is returned, but the attribute is missing after the return. 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 );

Another question on SO perked my interest in creating a setTimeout that returned a Promise and a timerId, yet would not break backwards patibility. This is the question I am referring to.

It simply asks if the inner return statement in the _.delay method of underscore.js is extraneous or serves a purpose. Here is the 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);
};

Considering setTimeout does not currently return a Promise, I proposed the idea that it is possibly there for future proofing, incase setTimeout does one day return a promise.

To do this setTimeout would need to return a timerId so that it can be canceled. So to return a Promise you would need to attach the timerId to the Promise, so that the Promise is returned and the timerId is accessable.

You could then modify clearTimeout to perform exactly how it does now when given a timerId, but for a Promise it uses Promise.timerId to clear the timeout and cancel the Promise. Of course Promise canceling would need to be implemented as well...

Anyhow... I started working on something for fun and came across something I haven't been able to explain. If you run the snippet below, you will see that the promise has .timerId attribute before it is returned, but the attribute is missing after the return. 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 );

Share Improve this question edited Jul 23, 2017 at 20:12 Kyle Richardson asked Jul 23, 2017 at 19:10 Kyle RichardsonKyle Richardson 5,6453 gold badges18 silver badges40 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 5

The then in:

pseudoSetTimeout( callback, 1000 )
    .then( ( val ) => {
      console.log( val );
    });

returns a new promise, which is not the one that pseudoSetTimeout returned. It is a promise with undefined as promised value, since the then callback does not return anything.

You could make it work by not applying then during the assignment:

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 );

Because then is crucial in the use of promises, and is often used in chaining them, it seems that the idea to attach a custom property to a promise loses on usefulness.

Really interesting question.

Not sure of how it's made internally in node, but if looking on the then code of bluebird is any indication : https://github./petkaantonov/bluebird/blob/master/src/thenables.js

My guess would be that the Promise returned is actually another object.

Due to the reasons mentioned in the other answers, I would return a 'tuple' instead of using a property on the promise:

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 );

发布评论

评论列表(0)

  1. 暂无评论