Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make superagent return a promise

I've been learning Node/Javascript, using promises from the start (I don't know how to not use promises and often wonder how others get along without them).

So I sometimes need to "promisify" simple stuff like reading a file with fs:

var readFile = function(path) {
    return new Promise(function(fulfill, reject) {
        fs.readFile(path, function(err, data) {
            if (err) { reject(err); }
            else { fulfill(data); }
        });
    });
};

And that's been working great. Now I need to do the same with superagent, but the chaining style it uses has me stuck.

var request = require('superagent');
request.get(...).set(...).set(...).end(callback);  // stuck!

I'd like to replace the end() method (or ignore it and add a new method) with one that returns a promise. Something like this...

var endQ = function() {
    return new Promise(function(fulfill, reject) {
        this.end(function(err, res) {     // "this" is the problem!
            if (err) { reject(err); }
            else { fulfill(res); }
        });
    });
};

// then I could say this:
request.get(...).set(...).set(...).endQ().then(function(res) {
    // happiness
}).catch(function(err) {
    // sad about the error, but so happy about the promise!
});

This question here has all kinds of advice about adding methods to objects, but it's hard to see what is definitive. I was especially worried by this answer. Much of the advice centers around starting with the object's "class" and adding the function to .prototype. Something like this....

// this part doesn't make sense
var requestInstance = new Request();   // no such thing in request as far as I know
requestInstance.prototype.endQ = endQ; // would be great, but no

See my problem? I want the JS equivalent of "subclassing" the request "class" and adding a method, but since its a module, I need to treat the request class as more or less opaque.

like image 604
user1272965 Avatar asked Mar 30 '16 15:03

user1272965


People also ask

What is superagent's request?

SuperAgent's request is a "thenable" object that's compatible with JavaScript promises and the async / await syntax. If you're using promises, do not call .end () or .pipe (). Any use of .then () or await disables all other ways of using the request. Libraries like co or a web framework like koa can yield on any SuperAgent method:

How to make a promise return the resolved value instead of [object]?

to call Promise.resolve with 1 to return a promise that resolves to 1. Then we use the await keyword to get the resolved value and assign that to d. Therefore, d is 1. To make a promise return the resolved value instead of [object Promise] with JavaScript, we can use the await keyword.

What are returned promises?

Since most people are consumers of already-created promises, this guide will explain consumption of returned promises before explaining how to create them. Essentially, a promise is a returned object to which you attach callbacks, instead of passing callbacks into a function.

Why does getpromise return a promise after 2000ms?

This happens because after making a call to getResult method, it in turns calls the getPromise method which gets resolved only after 2000 ms. getResult method doesn’t wait since it doesn’t returns a promise. So, if you return a promise from getResult method it can then be used to wait for the Promise to get resolved.


1 Answers

First of all superagent already supports promises:

request.get(...).set(...).set(...).then(response => {
    // handle it here
});

Note that unlike regular then, the then here isn't a promise then - it rather actually invokes the request and acts lazily.

Second, what you want to do is pretty simple:

Object.getPrototypeOf(request.get(...)).endQ = function() { // get to prototype and define
  /* your code here */
};

Here is what superagent itself does:

exports.then = function then(resolve, reject) {
  if (!this._fullfilledPromise) {
    var self = this;
    this._fullfilledPromise = new Promise(function(innerResolve, innerReject){
      self.end(function(err, res){
        if (err) innerReject(err); else innerResolve(res);
      });
    });
  }
  return this._fullfilledPromise.then(resolve, reject);
}
like image 196
Benjamin Gruenbaum Avatar answered Oct 26 '22 23:10

Benjamin Gruenbaum