1

I am not sure if what I am expecting is correct or not, but if Promise is like any other JavaScript class, it should have a this context.

But the following code surprises me.

var promise = new Promise(function (resolve, reject) {
    console.log(this === window); // Prints true
});

Am I missing the concept of native Promises here?

My objective is to attache some property to the promise object while creating it, and be able to access it later.

I know the callback function passed in the Promise isn't in any context and would be called just like a plain function. But is there a way to attach the property to each promise returned?

this.someProp = someobj.returnVal();

More Info

Basically, I am making an ajax request inside the promise, and I want to store the request object in the promise so that I can use it to abort the request when I want. by adding a polyfill abort to the Promise.prototype

Here's the actual code.

var _request;

const promise = new Promise(function (resolve, reject) {

  this._request = superagent.get(url)
     .end((error, res) => { resolve(res); }); // What I expect to work 

  _request = superagent.get(url)
     .end((error, res) => { resolve(res); }); // But I have no this context
});

Promise.prototype.abort = function () {
  this._request.abort(); // Can't do this
}
Salman
  • 8,694
  • 6
  • 35
  • 70
  • Can you describe what problem makes you want to attach something to the promise because there is probably a better way to solve your issue. – jfriend00 Sep 28 '15 at 04:42
  • 1
    @jfriend00 _jqXHR_ - doesn't that assume jquery? `fetch` https://developer.mozilla.org/en/docs/Web/API/Fetch_API may be the answer (there's a polyfill for IE) – Jaromanda X Sep 28 '15 at 04:47
  • Yeah, my mistake. I thought it was jQuery. Please show your actual code. Perhaps you need to return an object that has both a promise and the XHR object in it rather than just a promise. – jfriend00 Sep 28 '15 at 04:49
  • Please post the code. You will ALWAYS get higher quality answers if we can see the actual code you are trying to use rather than trying to answer an abstract question that is usually about the solution you're trying to follow rather than a description of the actual overall problem. – jfriend00 Sep 28 '15 at 04:50
  • @JaromandaX - does `fetch()` return a promise with an abort method? The OP wants to be able to use promises for the ajax call, but also able to call `abort()`. – jfriend00 Sep 28 '15 at 04:54
  • good point @jfriend00 – Jaromanda X Sep 28 '15 at 04:56
  • @jfriend00 Agreed... Added the actual code. Is there a different way to solve this? May be inheriting a `MyPromise` from `Promise` and `bind`ing the callback to it. Or may be a completely different approach, please suggest. – Salman Sep 28 '15 at 04:57
  • @JaromandaX It seems `fetch` returns promise as well as has `abort`. I'll check that. But isn't it interesting to solve this original problem as well! – Salman Sep 28 '15 at 05:01
  • I think the problem is because you are using `arrow` function – mido Sep 28 '15 at 05:01
  • @mido22 Appologies, I tried without arrow as well. Let me update – Salman Sep 28 '15 at 05:02
  • @JaromandaX Oops, Nope, it doesn't. I forgot to remove my polyfilled `abort`. :P It uses `Promise` internally it seems. – Salman Sep 28 '15 at 05:07
  • It is dangerous to try adding custom properties to promises because each `.then()` creates a new promise and thus loses anything custom attached to the prior promise. I think I'd just return both an object from your function that had both the promise and the request object in it and then the caller can access either. Or, you could put the promise on the request object because it can more easily be modified. – jfriend00 Sep 28 '15 at 05:08
  • @Салман - I think you are mistaken about fetch having an abort method. – Jaromanda X Sep 28 '15 at 05:08
  • @jfriend00 I'm not sure if I follow you, could you please post a simple snippet showing what you mean. – Salman Sep 28 '15 at 05:10
  • Btw guys, [superagent-promise](https://github.com/lightsofapollo/superagent-promise) seems to do what I want. But it wraps the whole `superagent` and subclass it. Still I'll wait for your expert opinions. – Salman Sep 28 '15 at 05:13
  • I posted an answer with some of the ideas mentioned. Personally, I use the `request` module and promisify it with Bluebird's `.promisifyAll()` method and have no tried to abort. – jfriend00 Sep 28 '15 at 05:24

1 Answers1

1

Here's the idea you asked me to post that returns an object that contains both the request object and the promise and then the caller can use either one:

function getInfo(url) {
    var req = superagent.get(url);
    var p = new Promise(function(resolve, reject) {
        req.end(function(error, res) { 
            if (error) return reject(error);
            resolve(res); 
        });
    });
    // return an object with both promise and request object in it
    // so caller can use either
    return {promise: p, req: req};
}

var ret = getInfo(myURL);
ret.promise.then(function(res) {
    // handle response here
}, function(err) {
    // handle error here
});

// you could also do this at any time
ret.req.abort();

As it turns out, you could use this same structure to put the request object on the promise like this (though I wouldn't recommend it because chaining promises creates new promises thus losing the custom properties on the original promise):

function getInfo(url) {
    var req = superagent.get(url);
    var p = new Promise(function(resolve, reject) {
        req.end(function(error, res) { 
            if (error) return reject(error);
            resolve(res); 
        });
    });
    p.req = req;
    return p;
}

Or, you could put the promise on the request object (which is safer):

function getInfo(url) {
    var req = superagent.get(url);
    var p = new Promise(function(resolve, reject) {
        req.end(function(error, res) { 
            if (error) return reject(error);
            resolve(res); 
        });
    });
    req.promise = p;
    return req;
}
jfriend00
  • 580,699
  • 78
  • 809
  • 825