4

One thing puts me off with Promise is that it is difficult to grasp with resolve and reject. Also the need of wrapping for Promise is ugly. Unless you use it very often, I tend to forget how to use them over time. Besides, code with Promise is still messy and hard to read. Hence I don't really like using it at all - because it has not much different from the callback hell. So I thought with ES7 await, I can avoid using Promise and giving me some more faith in JavaScript, but it seems that it is not the case. For instance:

const getOne = async () => {
    return Weather.findOne(options, function(err, weather) {
        //
    });
}
const getWeather = async () => {
    const exist = await getOne();
    if (exist == null) {
        return new Promise(function(resolve, reject) {
            // Use request library.
           request(pullUrl, function (error, response, body) {
                if (!error && response.statusCode == 200) {
                    // Resolve with the data.
                    resolve(body);
                } else {
                    // Reject with the error.
                    reject(error);
                }
            });
        });
    }
}

const insertWeather = async () => {
    try {
        const data = await getWeather();
    } catch (err) {
        res.set('Content-Type', 'application/json');
        return res.status(200).send('Error occurs: ' + err);
    }
}
insertWeather();

request(pullUrl, function (error, response, body) {} is an AJAX call from request package for nodejs.

I have to wrap it with Promise - but not precede it with await. Ideally this is what I imagine:

return await request(pullUrl, function (error, response, body) {...}

But if I do that, I will get the request object in return, instead of the data return from the request package - at this line:

const data = await getWeather();

Any ideas or solutions to avoid using Promise in the case such as the one above?

Run
  • 54,938
  • 169
  • 450
  • 748
  • 1
    FYI, there's a popular library called request-promise that saves you the hassle: https://www.npmjs.com/package/request-promise – nadavvadan Jul 04 '17 at 14:29
  • 1
    You can't replace Promise with await because well async/await is syntactic sugar to work with Promises. You could either promisify request package or use some generator based coroutine library that handles node style callbacks (but the later would be even harder to grasp) – Yury Tarabanko Jul 04 '17 at 14:31
  • 1
    Promises themselves are based on callbacks. The thing that differs them from 'callback hell' is that nesting is reasonably limited. So no, it's ok and supposed to be used in conjunction with `await`, not to be replaced by it. There's already https://nodejs.org/api/util.html#util_util_promisify_original in Node 8, and there are promisified packages for most major Node libraries. – Estus Flask Jul 04 '17 at 14:46

2 Answers2

5

You'll find bluebird and node.js now come with promisify to allow you to consume Node callbacks as promises when you need too. Alternatively, you can consider a functional reactive approach and use a library like RxJS which will handle promises, node callbacks and other data types into streams.

const promisify = require('utils').promisify // alternatively use bluebird
const request = require('request-promise');

const weatherFn = promisify(Weather.findOne);

const weatherOptions = {};

async function getWeatherIfDoesNotExist() {

 try {
   const records = await weatherFn(weatherOptions);

   if (records === null) {
     return await request('/pullUrl');
   }

 } catch(err) {
   throw new Error('Could not get weather');
 }
}

async function weatherController(req, res) {
  try {
    const data = await getWeatherIfDoesNotExist();
  } catch (err) {
    res.set('Content-Type', 'application/json');
    return res.status(200).send('Error occurs: ' + err);
  }
}

function altWeatherController(req, res) {

  return getWeatherIfDoesNotExist()
    .then((data) => { // do something })
    .catch((err) => {
      res.set('Content-Type', 'application/json');
      return res.status(200).send('Error occurs: ' + err);
    })
}
sidhuko
  • 3,274
  • 1
  • 17
  • 22
  • 1
    thanks for the code. it looks so much better with plain Promise! – Run Jul 04 '17 at 15:20
  • 1
    We're starting to look like a strongly type language! :) yay for TC39 – sidhuko Jul 04 '17 at 15:39
  • 1
    what is TC39 about? – Run Jul 04 '17 at 15:41
  • 3
    From Exploring JS: "TC39 (Ecma Technical Committee 39) is the committee that evolves JavaScript. Its members are companies (among others, all major browser vendors). TC39 meets regularly, its meetings are attended by delegates that members send and by invited experts. Minutes of the meetings are available online and give you a good idea of how TC39 works." – Cisco Jul 04 '17 at 16:33
1

As mentionned in the documentation here, you will need to wrap request with interfaces wrappers like request-promise (or you can find alternatives interface in the documentation) in order to return a Promise from request.

Jérôme
  • 1,060
  • 1
  • 7
  • 18