71

I have a spec from a client for an implementation of a method in a module:

 // getGenres():
 //  Returns a promise. When it resolves, it returns an array.

If given an array of genres,

['comedy', 'drama', 'action']

Here is a skeleton method with a promise:

MovieLibrary.getGenres = function() {
  var promise = new Promise(function(resolve, reject) {
    /* missing implementation */
  });

  return promise;
};

Can the promise be made to return the data found in the genres? Is there a better way to achieve the spec description?

2
  • 11
    Promises don't "return" values, they pass them to a callback (which you supply with .then()). The spec simply sounds confused to me. It's probably trying to say that you're supposed to do resolve([genre1, genre2, ...]); inside the promise implementation.
    – Ixrec
    Apr 22, 2015 at 23:07
  • A promise can also be rejected (instead of resolved) in case of an error/exception, and in such case the returned promise is 'caught' with the Promise.catch. In case of using async / await syntax one should use the try-catch block to enclose the awaited statement(s). Note there is also a Promise.finally.
    – prasad_
    Nov 17, 2021 at 11:25

3 Answers 3

64

It sounds like you aren't understanding how promises are used. You return a promise. Then, later when your code resolves the promise, it resolves it with a result and that result is passed to the .then() handler attached to the promise:

MovieLibrary.getGenres = function() {
  var promise = new Promise(function(resolve, reject) {
    /* missing implementation */
    resolve(result);
  });

  return promise;
};

MovieLibrary.getGenres().then(function(result) {
    // you can access the result from the promise here
});
2
  • Probably, you don't understand why this might be needed. In environment, like React Native with Redux with Realm, I have to put initial state to Redux createStore. It should be fetched from Realm, but it returns promise. I just want to block until it returns data as this should be very fast and simple. Instead I get problems how to combine Realm promises and usual JSON object for createStore()
    – likern
    Dec 26, 2018 at 19:19
  • 3
    @likern Browser Javascript can't block... end of story.
    – user253751
    Jul 17, 2020 at 11:18
59

Updated answer for ES2017

The method will still return a promise, but you can use const value = await (the promise) to assign a value to a variable

await stops executing until the Promise has resolved (ie, has a value). Unlike using .then() you can just keep awaiting values as you run various functions that return promises, and execution continues onto the next line (this is called 'direct style). It's also much nicer to look at than .then() everywhere, since it's consistent with the rest of JavaScript.

// Example function that returns a Promise that will resolve after 2 seconds
var getGenres = function() {
  return new Promise(function(resolve) {
    setTimeout(function(){
      resolve(['comedy', 'drama', 'action'])
    }, 2000);
  });
}

// We start an 'async' function to use the 'await' keyword
(async function(){
  var result = await getGenres()
  console.log('Woo done!', result)

  // But the best part is, we can just keep awaiting different stuff, without ugly .then()s
  var somethingElse = await getSomethingElse()
  var moreThings = await getMoreThings()
})()

Await is supported in all current browsers and node

5
  • 9
    Oh hey wow look, 3 SE questions on this subject and finally we have an actual answer!
    – Andrew
    Aug 27, 2019 at 21:22
  • Babel will also compile ES6 async/await to ES5 compatible code. Common Component within frameworks like Angular. Mar 20, 2020 at 1:53
  • value = await (the promise) requires one to be inside an async context, thus defeating the purpose
    – smac89
    Apr 19, 2021 at 20:03
  • @smac89 You can use an IIFE or newer node supports top level await. Apr 19, 2021 at 20:07
  • 1
    Got it. I was using the repl, so I had to launch it with node --experimental-repl-await
    – smac89
    Apr 19, 2021 at 20:29
1

The way I like to do it is to create a let variable and assign the 'then' result to that variable. Const won't work because it will give you an error. It will be like let value_result = function_that_returns_promise.then(result => value_result = result)

For your example, I made the method into a function for simplicity:

const genres = ['comedy', 'drama', 'action'];

function getGenres() {
  var promise = new Promise( (resolve, reject) => {
     let result = genres[0]  //just picking out the first one as example
     resolve(result)
  })
  return promise
}

const result_as_promise = getGenres()
console.log(result_as_promise);

//output:
//Promise { 'comedy' }

let result_as_value = getGenres().then(result => result_as_value = result)

setTimeout(function () {
  console.log(result_as_value);
}, 0);

//output:
//comedy

You have to use setTimeout if you are running through node (otherwise you'll get undefined error due to racing condition); if running it in browser console, then you prob don't need the setTimeout.

1
  • I don't think you need to assign the promise to result_as_value in let result_as_value = getGenres().then(...). Just declaring the variable and the assignment in the then(result => result_as_value = result) suffice. The reason this works is because the callback to setTimeout(...) executes after all of the other user code has executed, which includes resolving the getGenres() promise. This is related to how the event loop works. See how Node.js does it, nodejs.org/en/docs/guides/event-loop-timers-and-nexttick Nov 19, 2021 at 14:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.