216

I'm still struggling with promises, but making some progress thanks to the community here.

I have a simple JS function which queries a Parse database. It's supposed to return the array of results, but obviously due to the asynchronous nature of the query (hence the promises), the function returns before the results, leaving me with an undefined array.

What do I need to do to make this function wait for the result of the promise?

Here's my code:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    var promise = query.find({
               success: function(results) {
               // results is an array of Parse.Object.
                             console.log(results);
                             //resultsArray = results;
                             return results;
               },

               error: function(error) {
               // error is an instance of Parse.Error.
                             console.log("Error");
               }
    });                           

}
mac_55
  • 4,130
  • 7
  • 31
  • 40

4 Answers4

85

Instead of returning a resultsArray you return a promise for a results array and then then that on the call site - this has the added benefit of the caller knowing the function is performing asynchronous I/O. Coding concurrency in JavaScript is based on that - you might want to read this question to get a broader idea:

function resultsByName(name)
{   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    return query.find({});                           

}

// later
resultsByName("Some Name").then(function(results){
    // access results here by chaining to the returned promise
});

You can see more examples of using parse promises with queries in Parse's own blog post about it.

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • can you tell me what's the support of this? IE9 supports this? – sandrina-p Nov 01 '16 at 15:32
  • Yes, but Parse itself is mostly dead so there's that @SandrinaPereira. This is parse _cloud_ code. – Benjamin Gruenbaum Nov 01 '16 at 15:54
  • 4
    Ah so this is not only pure javascript? I was looking for a way to do this (wait for a function to finish to start another) but only with pure javascript.. – sandrina-p Nov 01 '16 at 16:27
  • The question is about parse code, not promises. Promises can work (with a library) in any browser. Bluebird runs in IE6 and netscape 7. – Benjamin Gruenbaum Nov 01 '16 at 16:51
  • 45
    I have been reading SO for two days now, and still, nobody has solved this. This accepted answer is the same as every other. The function returns a Promise, not a value as the OP requested. Why is this answer marked as accepted? – iGanja Dec 10 '19 at 18:39
  • 3
    I have been reading SO for 3 minutes but am nevertheless annoyed that people can't understand that use cases are different and if I am looking to make something synchronous it doesn't mean I am a beginner who doesn't know what they need. – Alexandre G Jun 19 '22 at 12:35
  • 1
    That's fine, 82 people found this answer useful, feel free to post alternative answers using one of the ways to force synchronization that result in very poor performance and if people find that useful they'll upvote it. – Benjamin Gruenbaum Jun 20 '22 at 08:57
  • Where is `resultsArray` even used? – Shmack Dec 15 '22 at 21:18
38

What do I need to do to make this function wait for the result of the promise?

Use async/await (NOT Part of ECMA6, but available for Chrome, Edge, Firefox and Safari since end of 2017, see canIuse)
MDN

    async function waitForPromise() {
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    }

Added due to comment: An async function always returns a Promise, and in TypeScript it would look like:

    async function waitForPromise() {
        // let result = await any Promise, like:
        let result: Promise<string> = await Promise.resolve('this is a sample promise');
    }
Martin Meeser
  • 2,784
  • 2
  • 28
  • 41
  • 14
    The async function will still return a promise object if called without an await (or in non asynchronous code). Check the result of console.log(waitForPromise()) if you are uncertain. A check of console.log(result) within the async function _will_ print out what you expect, but the return from the async function happens immediately without blocking and returns a promise. Blocking in javascript is usually very bad since it's a single threaded application and blocking will starve any other pub/sub clients of notifications essentially bringing the entire app to it's knees. – SRM Jun 15 '18 at 19:59
  • 7
    .net has .wait() on the "promise" like task class. Is Javascript missing this feature? I need to wait on something before exiting my node command-line tool that may pipe its output to another tool. "await" only works inside async functions. Meaning it doesn't work outside the scope of a promise. – TamusJRoyce Oct 31 '18 at 19:19
  • @SRM I feel like your comment is based on a misinterpretation of the sample - it is about the "inner" Promise.resolve (as the most simple Promise example) so there is no outer caller as you are stating in your comment. So I decided to update the answer. – Martin Meeser Nov 07 '18 at 15:42
  • @TamusJRoyce Guess that is a question on its own but I think in C# you can use Task.ContinueWith(Task), which is the same idea as you see in the accepted answer (where it is called "then()" ). – Martin Meeser Nov 07 '18 at 15:52
  • I think I see now. I can pretty much wrap my entire script in one huge async function. And call that function as the last line of my script. That function would still be a little bit of boiler plate. But way less than I previously perceived. I'm not used to writing functions within functions. Thank you @MartinMeeser! – TamusJRoyce Nov 11 '18 at 15:23
  • Is that function in use in ES5? – Merve Gül Feb 27 '21 at 10:00
3

You're not actually using promises here. Parse lets you use callbacks or promises; your choice.

To use promises, do the following:

query.find().then(function() {
    console.log("success!");
}, function() {
    console.log("error");
});

Now, to execute stuff after the promise is complete, you can just execute it inside the promise callback inside the then() call. So far this would be exactly the same as regular callbacks.

To actually make good use of promises is when you chain them, like this:

query.find().then(function() {
    console.log("success!");

    return new Parse.Query(Obj).get("sOmE_oBjEcT");
}, function() {
    console.log("error");
}).then(function() {
    console.log("success on second callback!");
}, function() {
    console.log("error on second callback");
});
mash
  • 14,851
  • 3
  • 30
  • 33
2

You don't want to make the function wait, because JavaScript is intended to be non-blocking. Rather return the promise at the end of the function, then the calling function can use the promise to get the server response.

var promise = query.find(); 
return promise; 

//Or return query.find(); 
Community
  • 1
  • 1
html_programmer
  • 18,126
  • 18
  • 85
  • 158
  • 2
    Your whole callbacks thing with the `success:` bit is off. – Benjamin Gruenbaum Jan 03 '15 at 21:18
  • Or better: `return query.find();`. – mash Jan 03 '15 at 21:21
  • Also ok. I'll just leave it like this for illustrative purpose but added it as comment. – html_programmer Jan 03 '15 at 21:22
  • I tried this but the results seem to be undefined. resultsByName("name").then(function(results){ console.log("got array "+results.count); }); – mac_55 Jan 03 '15 at 21:59
  • As test, try: `var promise = resultsByName("name");` and `console.log(promise);` In the console you should see a promise. Let me know what you find. Also, check in the network tab if anything is actually returned. – html_programmer Jan 03 '15 at 22:03
  • I ran the log statement directly after declaring the promise variable. Got this in the log: {"_resolved":false,"_rejected":false,"_resolvedCallbacks":[],"_rejectedCallbacks":[]} – mac_55 Jan 03 '15 at 22:10
  • What you see in the console is an unresolved Parse promise. According to the docs https://www.parse.com/docs/js/symbols/Parse.Promise.html, your result should be in the console when you use: `promise.then(function(results) { console.log(results); });`If something gets returned from the server, you have to get a result. – html_programmer Jan 03 '15 at 22:19
  • 1
    Thanks, there must've been some sort of error inside the results function. It's working now. I changed my console.log to results.length and can see that there's 1 entry in my returned array :) – mac_55 Jan 03 '15 at 22:30
  • Sfter struggling a lot with promises I disagree with "intended to non-blocking". In case of Apple MusicKit JS you certainly don't want to write whole app in then() block therefore you HAVE to wait and block stuff until promise is resolved. – Sebastian Dec 17 '21 at 21:08
  • @Sebastian That's not really how it works. You probably want to use async-await these days. What you want to do is to write code that looks synchronous, but actually performs asynchronously. – html_programmer Dec 17 '21 at 21:09