What does Uncaught (in promise) mean?
Asked Answered
C

4

14

I'm trying to learn what Promise is, so I started following this guide.

I copied this code from the guide and tried it in my developer console:

var promise = new Promise(function(resolve, reject) {
  // do a thing, possibly async, then…

  if (false) {
    resolve("Stuff worked!");
  }
  else {
    reject(Error("It broke"));
  }
});

I get an error saying Uncaught (in promise) Error: It broke. I don't understand what this means. Can anyone explain?

Corinnacorinne answered 2/9, 2019 at 2:46 Comment(1)
It means that a Promise rejected, and that rejection wasn't handled anywhereColorific
U
15

A promise can be resolve or rejected. If it's if/when it's resolved any then functions will be called. If it's rejected any catch functions will be called. If you don't provide any catch functions then promise might helpfully print that warning.

function test(fail) {
  return new Promise((resolve, reject) => {
    if (fail) {
      reject();
    } else {
      resolve();
    }
  });
}

// will print rejected 1
test(true)
  .then(() => { console.log('resolved 1'); })
  .catch(() => { console.log('rejected 1'); })

// might generate the error telling you the promise
// was rejected but you didn't provide a catch function
test(true)
  .then(() => { console.log('resolved 2'); })

Note that message is a helpful warning by the browser/JavaScript engine. You don't have to catch rejected promises but usually you want to so the message is helpful.

details

It's important to note how promises work. When you call then(someFunc) they effectively put someFunc on a list of functions to be called later. If the promise is already fulfilled they'll call every function on the list and clear the list. If the promise is not fulfilled they'll do nothing until it is. The same for catch except it's a different list.

Here's an example

function makePromiseParts() {
  let resolve;
  let reject;
  const promise = new Promise((_resolve, _reject) => {
    log('--in promise--');
    resolve = _resolve;
    reject = _reject;
  });
  return {
    promise,
    resolve,
    reject,
  };
}

function wait() {
  return new Promise(resolve => setTimeout(resolve));
}

async function main() {
  {
    log('--start--');
    
    const p = makePromiseParts();
    
    log('--after make promise--');

    p.promise.then(() => { log('then 1'); });
    p.promise.then(() => { log('then 2'); });

    log('--before resolve--');

    p.resolve();

    log('--after resolve--');
    
    await wait();

    log('--after waiting--');

    p.promise.then(() => { log('then 3'); });
    p.promise.then(() => { log('then 4'); });

    log('--before waiting--');
    
    await wait();

    log('--end--');
  }
  
  await wait();
  log(' ');

  {
    log('--start--');
  
    const p = makePromiseParts();

    log('--after make promise--');

    p.promise.catch(() => { log('catch 1'); });
    p.promise.catch(() => { log('catch 2'); });

    log('--before reject--');

    p.reject();

    log('--after reject--');
    
    await wait();

    log('--after waiting--');

    p.promise.catch(() => { log('catch 3'); });
    p.promise.catch(() => { log('catch 4'); });

    log('--before waiting--');
    
    await wait();

    log('--end--');
  }

}
main();

function log(...args) {
  const elem = document.createElement('pre');
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}
pre { margin: 0; }

To put it another way, then takes a function that says call this function if and when you're resolved and catch takes a function that says call this function if and when you're rejected.

Ubiquitous answered 2/9, 2019 at 2:49 Comment(2)
Oooooohhh...I see. The argument function(resolve,reject) in the new Promise() gets fired pretty much around the time it was declared. I mistakenly thought function(resolve,reject) would be a callback function that is only fired if I ran a promise.then(fn1,fn2). Your sample code helped me realize this.Corinnacorinne
The functions passed to then are called later. the function passed to new Promise is called immediately.Ubiquitous
R
5

It means your Promise threw an error that was not caught.

i.e. you did not call .catch() on your promise.

In your case, if(false) will never evaluate to truthy, so your promise gets rejected.

Romaineromains answered 2/9, 2019 at 2:49 Comment(0)
L
0

Good thread. I spent a lot of time on it. Mostly getting my .catch usage correct (not getting "Uncaught"). Here is a minimal example of what works for me:

<!DOCTYPE html>
<html>
  <head>
    <title> promise await .then .catch  </title>
    <meta charset="UTF-8">    
    <script>
  "use strict"; 
  let fnresolve, fnreject; // the functions are saved here
  let nres=0, nrej=0; // counters
window.onload = async function() {  
  zlog (''); 
  while (true) {
    let p = new Promise((res, rej) => { fnresolve = res; fnreject=rej; } );
    await p
      .then( (what) => { nres+=1; zlog(what); } )
      .catch((what) => { nrej+=1; zlog(what); } );
  }
}
function zlog(msg) {
  if (msg!='') document.getElementById('zlog').innerHTML += nres+' resolves, '+nrej+' rejects, this one was '+msg+'<br />';
  document.getElementById('zlog').innerHTML += 'push either button<br />';
}
    </script>
  </head>
  <body>
<button onclick='fnresolve("OK");'> RESOLVE </button>
<button onclick='fnreject("NG");''> REJECT </button><br /><br />
<div id='zlog'></div>
  </body>
</html>
Leeds answered 26/2 at 21:10 Comment(0)
S
0

In my case the issue was caused because I've forgot to add the await before async function call:

async function foo() {
  throw Error("error");
}
async bar(f) {
  /*await*/ f();
}
try {
  await bar(foo);
} catch (e) {
}

Uncomment the await to fix the error.

Symphonist answered 31/7 at 17:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.