This page looks best with JavaScript enabled

Newbie Mistakes in Creating Promises in Javascript

 ·   ·  ☕ 5 min read

Promises and promise chaining - really powerful tools to use and make your life as easy as it can be. Until you are stuck in an error that no one seems to have a clue about.

Let us see some common errors and how to fix them.

1. Not use error handling in promises

It does not demand a lot, people. Just do it. (Oh, wait I have been guilty of it as hell.)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
let promiseToLog = new Promise(function(resolve, reject) {
  console.log("started");
  setTimeout(function() {
    resolve(1);
  }, 300);
});
console.log("promise initialized");

let res = 2;
promiseToLog.then(function(val) {
  console.log(`promise ${val++}: `, (res *= 2));
  return val;
});
promiseToLog.catch(function(err) {
  console.log(`error: `, err);
});

Attach your promises with catch statements unless you are trying to do something magical. If there are no catch statements -

  • errors may silently go to a place that cannot be named
  • errors to caller may have the runtime engine shout at you with caps and everything
  • the world may end from a solar flare - sun can be bothered by promises without catches
2. Not leverage catch to its potential

Sure catch catches an error, but it may not stop execution by itself.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
let promiseToLog = new Promise(function(resolve, reject) {
  console.log("started");
  setTimeout(function() {
    resolve(1);
  }, 300);
});
console.log("promise initialized");

let res = 2;
promiseToLog
  .then(function(val) {
    console.log(`promise ${val++}: `, (res *= 2));
    throw "deliberate error";
    // return val;
  })
  .catch(function(err) {
    console.log(`error 1: `, err);
  })
  .then(function(val) {
    console.log(`promise ${val++}: `, (res *= 2));
    return val;
  })
  .catch(function(err) {
    console.log(`error 2: `, err);
  })
  .then(function(val) {
    console.log(`promise ${val++}: `, (res *= 2));
  });

/* output
started
promise initialized
promise 1:  4
error 1:  deliberate error

// logic continues after error
// no one sent val to next then, so NaN
promise NaN:  8 

promise NaN:  16
*/

If you want to do something about error - do that. If you want to boil it up the chain, use a throw <error>. You could deliberately suppress errors - but for Pete’s sake (if you are Pete, then do it for Neo’s sake), log errors. This will save you from hours of debugging why a particular script within a promise not do its thing.

Also, note that when you chain catch and want to boil it up all the way, you have to re-raise errors by throwing them at each stage until you don’t want them to raise any further.

3. Believe that everything goes as long as you have Promise.all()

It is an excellent approach to start parallel transactions and resolve them with one Promise.all(). But, if you are not managing your errors property - you can fail lot many more transactions even if one promise gets rejected.

The below code returns errors within promises. There is no exception to the caller.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
let promiseToLog1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("delay log"), 3000);
});

let promiseToLog2 = new Promise((resolve, reject) => {
  reject(new Error("immediate error"));
});

Promise.all([
  promiseToLog1.catch(error => {
    console.log("error: ", error);
    // handle error here, or better - boil it up
    // return error;
  }),
  promiseToLog2.catch(error => {
    return error.message;
  })
]).then(values => {
  console.log(values[0]); // delay log
  console.log(values[1]); // immediate error
});

/* output
delay log
immediate error
*/

Promise.all is also not async all the time.

1
2
3
4
5
let sum = Promise.all([]);
// immediately resolve

let prod = Promise.all(["something_not_a_promise"]);
// resolve async even if values are ignored
4. Use ‘clean’ promise chains that are not really chains

It is tempting to use the common promise syntax to create chains and change that to a “cleaner” syntax. Just have promiseToLog.then() each time instead of then attached to one another like so -

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
let promiseToLog = new Promise(function(resolve, reject) {
  console.log("started");
  setTimeout(function() {
    resolve(1);
  }, 300);
});
console.log("promise initialized");

let res = 2;
promiseToLog.then(function(val) {
  console.log(`promise ${val++}: `, (res *= 2));
  return val;
});

promiseToLog.then(function(val) {
  console.log(`promise ${val++}: `, (res *= 2));
  return val;
});

promiseToLog.then(function(val) {
  console.log(`promise ${val++}: `, (res *= 2));
});

/* output
started
promise initialized
promise 1:  4
promise 1:  8
promise 1:  16
*/

The code will not do chain promises - it just attaches multiple thens to a single promise. When the initial promise resolves, all three thens will simultaneously execute and cause a cacophony.

The results 4, 8, 16 are as expected because the value got multiplied by 2 in each of the function without considering the sequence. Look at promise 1 part of the string - it was supposed to increment if there was indeed a chain.

5. Cause potential race conditions

See example code in (3) - are you here to code or watch a race?

Do not start a bug that is potentially disastrous to debug.

6. Don’t mind the resources - they are infinite

If you are trying your hand at DB (or even file) manipulations - try to throttle the number of promises so that resources are available at the right time. Unless, you are starting a promise apocalypse - then invite me to the show, I will get popcorn.

7. Use promises

Yes, this is a thing.

Questionably smart people will be like - “Yo’ newbie - why you using promise/then/catch when there is async/await? Do you want help with that time machine to fast forward to the now?”.

Stay in touch!
Share on

Prashanth Krishnamurthy
WRITTEN BY
Prashanth Krishnamurthy
Technologist | Creator of Things