9

I having a problem (well two if I'm honest) getting a promise or a callback to work inside a switch-case. Here is the basic code.

switch (page) {

  case 'contact':

   alert('contact in switch');

   var promise = $.get(page +'.json');
   promise.then(function(data){
     console.log("Items back! ", data);                     
   });

  break;
  .......

  console.log("Response data: ", data); // This is undefined

I understand that due to the nature of async functions, the switch is falling through to the break before the data comes back, making data log as undefined. So I thought putting the break inside the callback would work but it doesn't. When I do that the app stops working entirely.

So I guess my first question is how do I make the switch-case "wait" until the data comes back before going to break.

The second problem I have is that I ultimately want to be able to reuse my switch by wrapping it in a function where the page argument is the title of the page the user is navigating to and the callback will pass back the data returned from the getPageData function. When I try this it results in an undefined error for the callback of the pageContentLoaderfunction.

For the record, the getPageDatain the code below is a separate function which performs a generic XMLHttpRequest. It's working fine because the data gets logged correctly in the callback.

pageContentLoader(page, function(data) {
                    console.log("Back with data ", data);   
});

function pageContentLoader(page, callback){
    var data;

            switch (page) {
                case 'contact':
                    console.log('contact in switch');
                    getPageData(page,function(data){
                      console.log("Contacts back! ", data);     
                    });             
                    break;    
                case 'blog':
                    console.log('blog in switch');
                    getPageData(page,function(data){
                        console.log("Posts back! ", data);      
                    });                 
                    break;    
                default:
                    alert('hey that page doesn't exist!');    
            } 
            callback(data); // results in callback undefined!!
}   

I am sure it is possible to make this work but I've tried everything I can find without any luck so far. If anyone has any pointers or wants to tell me what I am doing wrong within my code I'd be grateful!

mikeym
  • 5,705
  • 8
  • 42
  • 62
  • anything with a Promise is necessarily asynchronous - therefore you're trying to log `data` before it's populated ... and ... `data` is an argument to a callback function anyway, so it's not the same `data` you declared earlier ... you need to learn about scoping and asynchronous coding .... `to wait until the data comes back`, you can't, you need to rethink your code completely – Jaromanda X Oct 21 '16 at 21:48
  • in your second code snippet, call the callback inside the getPageData callbacks – Jaromanda X Oct 21 '16 at 21:50
  • 1
    I know and understand that it's async. My question is about getting the async nature of a promise to work inside a `switch case` without it falling through to the `break`. I am aware that the `data` is not logging because it hasn't come back yet. This is what I am trying to resolve. Thanks for input! – mikeym Oct 21 '16 at 21:52
  • you say `I know and understand that it's async` - and then you go on to say `the async nature of a promise to work inside a switch case without it falling through to the break` ... it's the async nature of the promise that is the reason it "falls through" to the break – Jaromanda X Oct 21 '16 at 21:56
  • 1
    @mikeym You need to put your switch into the async callback, and execute it then. You can't use data you don't have. – Carcigenicate Oct 21 '16 at 21:56
  • Sorry. Maybe I'm not being clear enough.If you take a look at my question again you'll see that I tried the break inside the promise specifically because I know the async nature of the promise was causing it to fall through. I'm not expecting it to work outside the promise if that's what you mean by `need to learn about scoping and asynchronous coding`. The console.log is just there to confirm what's happening. But the break won't work INSIDE the promise. That's my problem. I am trying to find a way to get my code to continue when and only when the promise is resolved and data is populated. – mikeym Oct 21 '16 at 22:28
  • Re: putting the outer callback inside the `getPageData` callback. I already tried this and it returns `callback undefined`. Sorry, I left out that important piece that would explain things better. The code above isn't the only thing I've tried and admittedly it looks like I'm not aware the data doesn't exist yet because of async, but I wanted to keep the question as short as possible. Again my main question is how to get a promise to work inside a switch structure. I can't get `break` to execute ONLY inside the async callback. I apologize for the confusion. – mikeym Oct 21 '16 at 22:53
  • @Carcigenicate Excellent. It was the golden words `put your switch into the async callback` that did it.I guess I was staring at it so long that I didn't realize it could be one single `getPageData` function with the switch INSIDE its single callback. I was thinking about it backward with a `getPageData` inside each `case` statement. Thanks! – mikeym Oct 21 '16 at 23:35
  • 1
    @mikeym No problem. Sometimes things just need to be reworded. – Carcigenicate Oct 21 '16 at 23:36

4 Answers4

6

Just ran into to this problem earlier, solved it as follows:

async getResolvedPromises(myObject) {
    const promises = await Object.keys(myObject).map(async (k) => {
        switch (k) {
            case '1':
                const firstPromise = await asyncCallNumber1()
                return firstPromise
            case '2':
                const secondPromise = await asyncCallNumber2()
                return secondPromise
            case '3':
                const thirdPromise = await asyncCallNumber3()
                return thirdPromise
            default:
                return
        }
    })

    const data = await Promise.all(promises)
    return data
}
rc_dz
  • 461
  • 4
  • 20
2

Here's a recent example in Typescript that I've adapted:

private pageContentLoader = async (): Promise<any> => {
    try {
        switch(page) {
            case 'contact':
                return await getPageData(page).then((data) => {
                    console.log("Contacts back! ", data);
                    return data;
                })
            case 'blog':
                return await getPageData(page).then((data) => {
                    console.log("Posts back! ", data);
                    return data;
                })
            default:
                return 'Page does not exist';
        }   
    } catch (err) {
        throw err;
    }
}


private getPageContent = async () => {
    try {
        const contactPageData = await pageContentLoader('contact');
        const blogPageData = await pageContentLoader('blog');
    } catch (err) {
        throw err;
    }
};
Jawa the Hutt
  • 73
  • 1
  • 1
  • 4
0

Here's a solution using the Promise constructor:

pageContentLoader('blog').then(function(data)
{
 console.log("Call to pageContentLoader results: ", data);   
});

function pageContentLoader(page)
{
 switch (page) {
  case 'contact':
   return new Promise(function(resolve)
   {
    console.log('contact in switch');
    getPageData(page).then(function(data)
    {
     console.log("pageContentLoader results: ",data);
     resolve(data)
    });
   });
   break;    
  case 'blog':
   return new Promise(function(resolve)
   {
    console.log('blog in switch');
    getPageData(page).then(function(data)
    {
     console.log("pageContentLoader results: ",data);
     resolve(data)
    });
   });
   break;    
  default:
   return new Promise(function(resolve)
   {
    console.log('default in switch');
    console.log("pageContentLoader results: doesn't exist");
    resolve("page doesn't exist");
   });
 } 
}

function getPageData(page)
{
 return new Promise(function(resolve)
 {
  window.setTimeout(function()
  {
   console.log('getPageData executed')
   resolve(page);
  },2000);
 });
}
enter code here
dcorsello
  • 463
  • 1
  • 4
  • 11
-1

For the first problem: You are trying to load a value of something that might not have been defined. As said, you need to think about learning some tips and tricks of asynchronous coding but here's a solution :

  switch (page) {
    case 'contact':
      alert('contact in switch');
      $.get(page +'.json').then(function(data){
        /* all the code AFTER fulfilling 
           the promise should BE here
         */
        handle_data(data);
      });
    break;

  //console.log("Response data: ", data); this should not be here
  ...
Youssef Bouhjira
  • 1,599
  • 2
  • 22
  • 38
W. Basmi
  • 57
  • 4
  • You should release that any operation that depends and is valid and only valid after data importation via ajax response, should be inside the block of the success function (function passed the then). – W. Basmi Oct 21 '16 at 22:06