Help needed with Node.JS Promise hell

I'm running into the same issue again and again regarding node.js Promises.

What i want is simple. I want to run a function that takes time and returns data.
I'm testing with console.log as where i want the data to be returned. somehow i am missing something every time i am running into this and finally decide to take another route.

the answers to the console.log's are allways 

makePromise { promiseSend: [Function], valueOf: [Function] }

why doesn't it wait for the prommis to be fulfilled?

 

function getRecentlyAddedMovies(){
    console.log("getRecentlyAddedMovies....");
    return kodi.videolibrary.getRecentlyAddedMovies({"limits": { "start" : 0, "end": 4 }}).then(function(r){
        return new Promise(function(resolve, reject) {
            const movieItems = r.movies
            console.log(movieItems)
            movieItems.map((items) => {
                resolve({
                    title: items.label,
                    thumbnailUri: items.thumbnail,
                    actionIdentifier: items.movieid
                });
            });
        });
    });
}

//this doesn't work
console.log (getRecentlyAddedMovies());

//this doesn't work
let x = getRecentlyAddedMovies();
console.log (x);

//this doesn't work
let x2 = getRecentlyAddedMovies().then((x) => {
    return (x)
});
console.log (x);

//this doesn't work
console.log (getRecentlyAddedMovies().then((x) => {
    return (x)
}));
Reply
5replies Oldest first
  • Oldest first
  • Newest first
  • Active threads
  • Popular
  • Niels de Klerk So a promise will always return a promise object as they are run asynchronously. For example, any of the code snippets below will always return a promise object, not the resolved value of the promise:
     

    var foo = Promise.resolve();
    var foo = new Promise((resolve, reject) => {});
    var foo = Promise.reject();
    

    Promises also go by other names in different languages, like Futures, Delay, Deferred but they essentially all the same thing - they are a proxy to describe a value that at the time of execution is not known.

    Forgive me if I sound patronising here, I don't mean to be at all, I'm just not sure of your level of knowledge with JavaScript as a language. So here is a very (high level) rough primer:

    JavaScript is single threaded which means that any code execution happens sequentially. In simple terms this mean that the previous block of code needs to execute and finish what it is doing before the next block. So if I was to write a function that needed to do a lot of computations and ran it, the next function to be executed would not be run until the previous one was done. For example:

    function verySlowFunction () {  //.. does something that takes a long time to execute }
    function veryFastFunction () { console.log('Im fast!'); }
    
    verySlowFunction(); // Lets say this take 20 seconds to execute and complete
    veryFastFunction(); // This will not be run until the verySlowFunction finishes its work (in 20secs time)
    

    In the example above, what has actually happened here is that the execution thread the program is running on is blocked for 20 seconds. That means that if some other code in our program wanted to execute whilst waiting for the verySlowFunction() to finish - it can't.

    To get around this, JavaScript uses what is called an "event loop" and a "callback queue". The event loop sits below the main execution thread of the program. Again, as a very basic explanation, the event loop gets work pushed to it along with a callback function. Once the event loop has finished that piece of work it calls the callback function you provided it and you know the work has been competed. The important thing to note here is that the work pushed to the event loop has been done away from the JavaScript execution thread - so it does not block it from running other code. The most simplest way of demonstrating this with a code example is like this:

    window.setTimeout(function () {
       console.log('Bye');
    }, 2000);
    
    console.log('Hello');
    

    The output from the above is: 'Hello', followed with 'Bye' after 2 seconds. The ran sequentially, but the 2 second timer did not block the main thread of execution.

    This isn't directly related to promises themselves but it does explain a fundamental piece of the JavaScript puzzle. So going back to promises, they are basically a nice API to use for asynchronous code execution in JavaScript and they are actually relatively new to the ECMAScript standard that JavaScript is based on. Prior to promises, working with asynchronous code in JavaScript was extremely messy:

    function timerOne(callback) {
       setTimeout(callback, 2000);
    }
    
    function timerTwo(callback) {
      setTimeout(callback, 2000);
    }
    
    function timerThree(callback) {
      setTimeout(callback, 2000);
    }
    
    // Run these three asynchronous tasks sequentially
    timerOne(function () {
       console.log('One done');
    
       timerTwo(function () {
          console.log('Two done');
    
          timerThree(function () {
            console.log('Three done, all finished');
          });
       });
    });

    The above is what is known as the "pyramid of doom" or "callback hell". Thats a very basic use case with no logic in the callbacks, but imagine if there were? It would be extremely hard to find out where you are in the code execution. Promises help us solve this readability and understanding problem:

    function timerOne() {
      return new Promise(resolve => setTimeout(resolve, 2000));
    }
    
    function timerTwo() {
      return new Promise(resolve => setTimeout(resolve, 2000));
    }
    
    function timerThree() {
      return new Promise(resolve => setTimeout(resolve, 2000));
    }
    
    // Run these three asynchronous tasks sequentially
    timerOne()
      .then(() => timerTwo())
      .then(() => timerThree());
    

    Because a promise always returns the same, consistent API (then(), catch()) we can easily start doing some very complicated async work in a very simple manner. If you don't like the look of the .then() approach then you could always use the new "await" keyword:

    function timerOne() {
      return new Promise(resolve => setTimeout(resolve, 2000));
    }
    
    function timerTwo() {
      return new Promise(resolve => setTimeout(resolve, 2000));
    }
    
    function timerThree() {
      return new Promise(resolve => setTimeout(resolve, 2000));
    }
    
    // Run these three asynchronous tasks sequentially
    await timerOne();
    await timerTwo();
    await timerThree();

    It's important to note that "await" is not supported everywhere and is only in node from version 7.6 onwards.

    An extremely good talk on explaining the way JavaScript executes can be found here

    I hope that has been some help.

    Like 2
    • Chris Shepherd that was of much help. I shouldn’t try to bring a async process back to a sync process. Thanks for the extensive post!

      Like 2
  • Niels de Klerk  I see one immediate problem with your code.

    movieItems.map((items) => {
                    resolve({
                        title: items.label,
                        thumbnailUri: items.thumbnail,
                        actionIdentifier: items.movieid
                    });
                });

    You're basically saying "For every movie item; resolve this promise". What you want to do, is store that data outside of the movieItems callback, then resolve() the promise with that data. The shorthand arrow syntax ie; => {}  is still a callback. 

    Here's some pseudo-code to help get you running.

    let movieItemResults = [];
    movieItems.map( item => {
        movieItemResults.push({
           ...
       }
    });

    resolve(movieItemResults);

    In addition to that, you have what looks like a function return statement directly before your Promise return (which only returns a Promise and not the actual result of the Promise).

    One thing to keep in mind is that callback hell can be a major mind obstacle to overcome for new developers. Almost all newer versions of node (I haven't checked what Neeo is running) can use something called async/await, that let's you write cleaner code that looks synchronous. It's not really important how it works behind the scenes, but if you must know, it pauses the current code block and allows other code to run. Something to keep in mind is that async functions return a promise as well.

    Some more pseudo code.

    async function getRecentlyAddedMovies() {
        let promiseOrAsyncResult = await onSomePromise();
        return promiseOrAsyncResult;
    }

    in other code that uses this:
    let myRecentlyAddedMovies = await getRecentlyAddedMovies();

    I hope this helps. Feel free to CC me in anything if you need further help.

    Like 1
    • Levi Roberts thanks. I slowly starting to get it. I’m not sure why it takes me such a long time but I’ll get there eventually :-)

      Like
    • Niels de Klerk not a problem at all! We all learn things at different speeds. Don't be hard on yourself. I am a software developer with 10+ years of experience and sometimes I still get hung up. Don't think twice about reaching out for a helping hand. I came from a PHP and C++ background and it took me a few months to understand Node's event loop system when I first got started.

      Like
Like1 Follow