skip to Main Content

The code below attempts to create a promise and assign it to an element in an object, and then call bar when the promise is fulfilled. However, the app.tabs.then doesn’t work ("Cannot read properties of null (reading ‘then’)"). Can anyone tell me how to fix this?

const app = {
   tabs : null,
   ...
};

document.getElementById('myid').addEventListener('click', function() {
   app.tabs = foo();  // returns a Promise
});

app.tabs.then(function() {
   bar();
});

EDIT

These are great answers, thanks, but there’s an issue: when I now get to functionbar, the promise has been fulfilled, and the PromiseResult is an array with one element, as expected. However, I can’t actually read the result. I normally read tabs[0].id from foo (when I run different versions of this code with async). Element 0 of PromiseResult contains an object named id, but I can’t read this as app.tabs[0].id – the debugger just says "Cannot read properties of undefined (reading ‘id’)". Any idea why?

5

Answers


  1. app.tabs only changes when you click on that element, so it’s null by the time the code that attaches .then is executed.

    The best way to go about it is to attached the continuation right when the promise is created:

    document.getElementById('myid').addEventListener('click', function() {
       app.tabs = foo();  // returns a Promise
       app.tabs.then(function() {
          bar();
       });
    });
    
    Login or Signup to reply.
  2. document.getElementById('myid').addEventListener('click', function() {
       app.tabs = foo();  // returns a Promise
    
       app.tabs.then(function() {
          bar();
       });
    });
    

    This code attaches the .then callback to the app.tabs Promise within the click event listener, ensuring that bar() will be executed when the Promise is resolved.

    Login or Signup to reply.
  3. As noticed @Wiktor Zychla
    Untill the click event happens, app.tabs equals to null
    it’s not possible to add property for that object. You can simulate a click event:

    document.getElementById('myid').addEventListener('click', function() {
       app.tabs = foo();  // returns a Promise
     });
    
     document.getElementById('myid').dispatchEvent(new Event("click"))
    
    Login or Signup to reply.
  4. Here is the working example :
    async/await in ES6 has great features over then/catch/finally

    let app = {
            tabs: null,
          };
    
          function foo() {
            return new Promise((resolve, reject) => {
              setTimeout(() => {
                resolve("HELLO WORLD");
              }, 2000);
            });
          }
    
          function bar(val) {
            console.log("The second function call : " + val);
          }
    
          async function myFunc() {
            //waits 2sec as setTimeout has 2000 ms to be resolved in promise
            let result = await foo();
            // provide result value from foo (promise) to bar function
            bar(result);
          }
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
      </head>
      <body>
        <button onclick="myFunc()">click</button>
        
      </body>
    </html>
    Login or Signup to reply.
  5. Storing this particular Promise (being in an event handler, and thus you’re in the middle of asynchronous things already) is just strange, you could rather store its result, something like

    document.getElementById('myid').addEventListener('click', function() {
       foo().then(function(result) {
          apps.tab = result;
          bar();
       });
    });
    

    Because whenever you’d need its result, you’d have to then() it anyway.

    Of course in 2023 you can probably use async, no contemporary browsers should complain about it:

    document.getElementById('myid').addEventListener('click', async function() {
       apps.tab = await foo();
       bar();
    });
    

    Or even use an arrow function:

    const apps = {
      tab: null
    };
    
    const foo = () => new Promise(resolve => resolve(42));
    
    document.getElementById('myid').addEventListener('click', async() => {
      apps.tab = await foo();
      bar();
    });
    
    function bar() {}
    <button onclick="alert(apps.tab);">Check</button>
    <button id="myid">Clicky</button>

    Click Check to see the initial null content, then Clicky, then Check to see the 42.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search