How do I incorporate promises into my code?

How do I incorporate promises into my code?
0

#1

I’ve been at this for a couple days, reading through tutorials and explanations but haven’t found a solution.

I’m working on my twitch app.

Here’s my logic for my JS:

  1. get stream data to see if user does not exist
  2. if they don’t, push html for non-existing accounts into array
  3. if user is not streaming, get channel data for channel info
  4. push html for offline accounts into array
  5. if they’re online, push html for online accounts into array
  6. join array with html in it and append it to page
  7. make page buttons and search for functional

What I currently have is messy: lots of nested callbacks, some of which are get requests.

I also get confused with scope since I’m doing this in a foreach method. You can see my code here http://codepen.io/ellereeeee/pen/eBZmKr

Thanks for any help!


#2

Read this … it’s a thread about Promises and multiple ajax requests.

Promises instead of callbacks

And it’s related to the Twitch.tv project as well.


#3

You’re doing a good job.

In addition to reviewing callbacks, a little code refactoring would help too. There is some duplicate coding that can be edited out.

I made a few small adjustments as an example.

http://codepen.io/cjsheets/pen/LbjNRN


#4

The idea behind promises is very simple - instead of returning a value you return a promise. Then when you call a function which returns promise, you use then which waits until promise is returned and do something with it. If you need two API calls with second being made with response from first, you just return new call from then and chain next then and so on (sounds a bit messy :slight_smile: )

Here is an example to illustrate:

const fakeAPICallReturnsPromise = (int) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(int * 2);
    }, 500)
  })
}

fakeAPICallReturnsPromise(1)
  .then(res => {
  console.log('First response:', res) // 2
  return fakeAPICallReturnsPromise(res)
  })
  .then(res => {
  console.log('Second response:', res) // 4
  return fakeAPICallReturnsPromise(res)
  })
  .then(res => {
  console.log('Third response:', res) // 8
  })
  .catch(err => console.log(err));

Three calls were made and everything looks very clean - no callbacks, no indentation.


#5

Thanks for taking the time to refactor my code a bit, I really appreciate it. It was really easy to understand how your edits are efficient.

I’ll be referencing your edits once I figure out a good way to use promises in my code.


#6

Thanks to everyone’s help, I was able to make successful get requests with promises, but I’ve hit another bump.

How do I make or use an existing function that lets me wait until I’ve gotten all data from Twitch’s API, then executes a function that appends data from those promises onto my webpage?

I’ve messed around with Promises.all but I’m wondering if I can’t use p1 and p2 as deferreds because they’re chained. I also tried $.when().done() but couldn’t use that properly either.

This is what I have so far. Here’s the codepen.

function APICallReturnsPromise(section, streamer) {
    return new Promise(function(resolve) {
      $.getJSON('https://wind-bow.hyperdev.space/twitch-api/' + section + '/' + streamer + '?callback=?', function(data) {
        resolve(data);
      }); // close getJSON
    }) // close promise
  } // close function
  
  streamersArr.forEach(function(streamer) {
    // this promise chains gets data for non existing accounts and offline users
    var p1 = APICallReturnsPromise('streams', streamer)
      // if data.status === 404, push not html for accounts that don't exist
      // if data.stream === null, return promise for channels data
      .then(function(data) {
        if (data.status === 404) {
           arr.push('<div class="result error row"><div class="col-xs-4 col-sm-2 col-md-2"><div class="pic"><img class="img-responsive" src="http://res.cloudinary.com/devvzv96d/image/upload/v1479131984/white-error-256_vix4cw.png"></div></div><div class="col-xs-6 col-sm-3 col-md-2 user result-text">' + streamer + '</div><div class="col-xs-8 col-sm-6 col-md-3 result-text"><em>Account does not exist</em></div></div>');
        } // close if
        else if (data.stream === null) {
          return APICallReturnsPromise('channels', streamer);
        }
      }) // close then 
      // push html for offline accounts
      .then(function(data) {
        arr.push('<a target="_blank" href="' + data.url + '"><div class="result offline row"><div class="col-xs-4 col-sm-2 col-md-2"><div class="pic"><img class="img-responsive" src="' + data.logo + '"></div></div><div class="col-xs-6 col-sm-3 col-md-2 user result-text">' + data.display_name + '</div><div class="col-xs-8 col-sm-4 col-md-3 result-text"><em>Offline</em></div></div></a>');
      }) // close then
    
    // this promise chains gets data for online users
    var p2 = APICallReturnsPromise('streams', streamer)
      // if data stream is null, get channel data
      .then(function(data) {
        if (data.stream != null) {
          return APICallReturnsPromise('channels', streamer);
        }
      }) // close then
      // push html for online channels
      .then(function(data) {
        arr.push('<a target="_blank" href="' + data.url + '"><div class="result online row"><div class="col-xs-4 col-sm-2 col-md-2"><div class="pic"><img class="img-responsive" src="' + data.logo + '"></div></div><div class="col-xs-6 col-sm-3 col-md-2 result-text user">' + data.display_name + '</div><div class="col-xs-6 col-sm-4 col-md-3 result-text"><em>' + data.game + '</em></div><div class="status hidden-xs col-sm-9 col-md-9"><span style="font-size:.8em;"><em>' + data.status + '</em></span></div></div></a>');
      }) // close then   
  
  }) // close foreach statement

I’m going to refactor my code that was suggesed by cjsheets once I get this working properly.

edit: I’m starting to wonder if incorporating promises is making things more complicated than they need to be…

update: I found a better to deal with asynchroncity than the setTimeout function. I didn’t use promises, but my app works. I think I’m going to refactor my code a bit more then move on… I’m a bit burnt out on this project. Thanks for the help guys, I learned a bit more about promises.