question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

What if something is a callback/async function AND a Promise

See original GitHub issue

Working with request-promise ;

e.g.

var rp = require('request-promise');
var Brakes = require('brakes');

var options = {
  uri: 'http://some-json-api.com/',
  json: true
};

var brake = new Brakes(request, { timeOut: 1000 });

return brake.exec(options)
  .then( response => {
    return processResponse(response);
  })
  .catch(e => {
    return processError(e.statusCode);
  });

request-promise wraps the normal request object, which is a function that has a callback parameter, and makes it return a promise. Wrapping it causes the behaviour to change because Circuit prefers async callback functions ; instead of the usual behaviour with these options which is for response to be an object representing the processed JSON response, and for errors to end up in .catch, all responses including errors end up in the .then() block because Circuit uses the default promise callback style instead of request-promise’s Promise wrapping.

Not sure the best way to resolve this but maybe an option to force the Promise treatment instead of using the callback style? Not a big thing to write code to work around this (and ditch request-promise in the process, since we’re not using it’s features).

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
awoldencommented, Sep 20, 2016

Hey @awilkins, I have used request-promise in some projects, and I have generally found that it is best to directly use or wrap request. Here is an example of how I wrap it in a promise for use in brakes.

function _requestWrapper(requestOpts) {
  return new Promise((resolve, reject) => {
    request(requestOpts, (err, response) => {
      if (err) {
        return reject(err);
      }
      // check status codes
      const errored = [500, 501, 502, 503, 504, 505].indexOf(response.statusCode) > -1;
      if (errored) {
        return reject(new InvalidResponseError(
          requestOpts.url,
          response.statusCode,
          response.body));
      }
      return resolve(response);
    });
  });
}

const brake = new Brakes(_requestWrapper, { timeOut: 1000 });
1reaction
awoldencommented, Oct 27, 2016

Hey @sveisvei,

Thanks for the feedback, but there is a problem with both of your examples and the suggestion to check if the passed function is a promise instead of doing the check to see if it is a callback. In your examples you use Promise.resolve() which returns a pre-resolved promise. However, the concept of brakes requires you to pass in a function reference that returns a promise (i.e. (opts) => Promise.resolve()). This is a subtle but important distinction. The first argument has to be a function reference because you may pass in different options to each request, and you will want a new execution on each call instead of referencing the same resolved promise. Moreover, with the lack of return typing in javascript, it is near impossible to do static analysis to determine if a function returns a promise.

These are all valid promise functions in js:

() => Promise.resolve();
() => new Promise(resolve => resolve());
() => {
  const deferred = Q.deferred;
  deferred.resolve();
  return deferred.promise;
}

You can’t realistically determine if a function returns a promise until after you have executed it, whereas with callback functions you can perform analysis on the function signature. If the analysis of the function signature is inadequate, that is something we can and should improve, but I don’t see how we can replace it with promise detection.

However, after looking at your examples, I think there is an improvement that could be made. Instead of relying solely on the callback detection in hasCallback we can add an option that forces brakes to treat the first argument as a callback-function.

That would look something like:

const brake = new Brakes((foo, bar) => bar(), {isFunction: true});

In that example, if the isFunction flag is set to true, it forces brakes to treat the first argument as a callback instead of a promise.

Likewise we could add:

const brake = new Brakes((foo, cb) => Promise.resolve(), {isPromise: true});

I would be excited and eager to approve a contribution that makes that change 👍

-Alex Wolden

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to use promises - Learn web development | MDN
Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the...
Read more >
Callbacks, Promises and Async/Await | by Sandeep Dinesh
A callback is a function that is passed to another function. When the first function is done, it will run the second function....
Read more >
Understanding the Event Loop, Callbacks, Promises, and ...
A promise represents the completion of an asynchronous function. It is an object that might return a value in the future. It accomplishes...
Read more >
Asynchronous JavaScript – Callbacks, Promises, and Async ...
Promises came along to solve the problems of callback functions. A promise takes in two functions as parameters. That is, resolve and reject...
Read more >
Async JS Crash Course — Callbacks, Promises, Async Await
Callback, Promises, and Async-await are a way to deal with asynchronous data. Asynchronous programming in JavaScript is a way in which the program...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found