Top 10 Promise Way to Build and Level Up your Coding Skills
Tags: node, typescript, devops, javascript
Published: 2020-02-24 01:38:45

There are many great ways to improve your coding skills, experiment with new technologies. The truth of the matter is to understand JavaScript and Promise. 

## Part 1:

```javascript
const prom = new Promise((res, rej) => {
  console.log('first');
  res();
  console.log('second');
});
prom.then(() => {
  console.log('third');
});
console.log('fourth');

// first
// second
// fourth
// third
```

`Promise` executes synchronously, `promise.then` executes asynchronously 

## Part 2: 

```javascript
const prom = new Promise((res, rej) => {
  setTimeout(() => {
    res('success');
  }, 1000);
});
const prom2 = prom.then(() => {
  throw new Error('error');
});

console.log('prom', prom);
console.log('prom2', prom2);

setTimeout(() => {
  console.log('prom', prom);
  console.log('prom2', prom2);
}, 2000);

// prom 
// Promise {<pending>}
// __proto__: Promise
// [[PromiseStatus]]: "resolved"
// [[PromiseValue]]: "success"

// prom2
// Promise {<pending>}__proto__: 
// Promise[[PromiseStatus]]: "rejected"[[PromiseValue]]: 
// Error: error
//     at <anonymous>:7:9
```

`promise` has three different states: 
 - pending
 - fulfilled
 - rejected

Once the status updated, `pending->fulfilled` or `pending->rejected`, it can be changed again. The `prom1` is different from `prom2` and both of them return new Promise status. 

## Part 3:

```javascript
const prom = new Promise((res, rej) => {
  res('1');
  rej('error');
  res('2');
});

prom
  .then(res => {
    console.log('then: ', res);
  })
  .catch(err => {
    console.log('catch: ', err);
  });

// then: 1
```

The `resolve` or `reject` only execute once even there is a resolve call after the reject. It won't execute.

## Part 4: 

```javascript
Promise.resolve(1)
  .then(res => {
    console.log(res);
    return 2;
  })
  .catch(err => {
    return 3;
  })
  .then(res => {
    console.log(res);
  });

// 1
// 2
```

Promises can be chained. When referring to chained calls, we usually think of returning this, but Promises do not. Each time a promise calls `.then` or `.catch`, a new promise will be returned, thus implementing chained calls.

## Part 5: 

```javascript
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('first')
    resolve('second')
  }, 1000)
})

const start = Date.now()
promise.then((res) => {
  console.log(res, Date.now() - start, "third")
})
promise.then((res) => {
  console.log(res, Date.now() - start, "fourth")
})

// first
// second 1054 third
// second 1054 fourth
```

A promise `.then` or `.catch` can be called multiple times, but here the Promise constructor is executed only once. In other words, once the internal state of a promise changes and a value is obtained, each subsequent call to `.then` or `.catch` will directly get the value.

## Part 6:

```javascript
const promise = Promise.resolve()
  .then(() => {
    return promise
  })
promise.catch(console.error)

// [TypeError: Chaining cycle detected for promise #<Promise>]
// Uncaught SyntaxError: Identifier 'promise' has already been declared
//    at <anonymous>:1:1
// (anonymous) @ VM218:1
```

The value returned by `.then` or `.catch` cannot be the promise itself, otherwise, it will cause an infinite loop.

## Part 7:

```javascript
Promise.resolve()
  .then(() => {
    return new Error('error');
  })
  .then(res => {
    console.log('then: ', res);
  })
  .catch(err => {
    console.log('catch: ', err);
  });

// then: Error: error!
// at Promise.resolve.then (...)
// at ...
```

Returning an error object in `.then` or `.catch` does not throw an error, so it will not be caught by subsequent `.catch`, you need to change to one of them:

```
return Promise.reject(new Error('error'))
throw new Error('error')
```

Because returning any non-promise value will be wrapped into a promise object, that is, return new Error ('error') is equivalent to return Promise.resolve (new Error ('error')).

## Part 8:

```javascript
Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)

  // 1
```

The argument of .then or .catch is expected to be a function, and passing in a non-function will results the result of value to be ignored such as `.then(2)` or `.then(Promise.resolve(3)`.

## Part 9:

```javascript
Promise.resolve()
  .then(
    function success(res) {
      throw new Error('Error after success');
    },
    function fail1(e) {
      console.error('fail1: ', e);
    }
  )
  .catch(function fail2(e) {
    console.error('fail2: ', e);
  });

//   fail2:  Error: Error after success
//     at success (<anonymous>:4:13)
```

`.then` can accept two parameters, the first is a function that handles success, and the second is a function that handles errors. `.catch` is a convenient way to write the second parameter of `.then`, but there is one thing to pay attention to in usage: `.then` the second error-handling function cannot catch the error thrown by the first successful function and subsequent ones. catch catches previous errors. Of course, the following code works if you want to rewrite: 

```javascript
Promise.resolve()
  .then(function success1 (res) {
    throw new Error('success1 error')
  }, function fail1 (e) {
    console.error('fail1: ', e)
  })
  .then(function success2 (res) {
  }, function fail2 (e) {
    console.error('fail2: ', e)
  })
```

## Part 10:

```javascript
process.nextTick(() => {
  console.log('1')
})
Promise.resolve()
  .then(() => {
    console.log('2')
  })
setImmediate(() => {
  console.log('3')
})
console.log('4');

// Print 4
// Print 1
// Print 2
// Print 3
```

Both `process.nextTick` and `promise.then` belong to microtask, while `setImmediate` belongs to macrotask, which is executed during the check phase of the event loop. A microtask is executed between each phase of the event loop (macrotask), and the beginning of the event loop is executed once.