Top 10 Promise Way to Build and Level Up your Coding Skills
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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.