Promise 想必大家都十分熟悉鞍爱,想想就那么幾個(gè) api涕蜂,可是你真的了解 Promise 嗎析校?本文根據(jù) Promise 的一些知識(shí)點(diǎn)總結(jié)了十道題礁哄,看看你能做對(duì)幾道长酗。
以下 promise 均指代 Promise 實(shí)例,環(huán)境是 Node.js桐绒。
題目一
const promise = new Promise((resolve, reject) => {
console.log(1)
resolve()
console.log(2)
})
promise.then(() => {
console.log(3)
})
console.log(4)
運(yùn)行結(jié)果:
1
2
4
3
解釋:Promise 構(gòu)造函數(shù)是同步執(zhí)行的夺脾,promise.then 中的函數(shù)是異步執(zhí)行的。
題目二
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
const promise2 = promise1.then(() => {
throw new Error('error!!!')
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {
console.log('promise1', promise1)
console.log('promise2', promise2)
}, 2000)
運(yùn)行結(jié)果:
promise1 Promise { <pending> }
promise2 Promise { <pending> }
(node:50928) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: error!!!
(node:50928) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
promise1 Promise { 'success' }
promise2 Promise {
<rejected> Error: error!!!
at promise.then (...)
at <anonymous> }
解釋:promise 有 3 種狀態(tài):pending茉继、fulfilled 或 rejected咧叭。狀態(tài)改變只能是 pending->fulfilled 或者 pending->rejected,狀態(tài)一旦改變則不能再變烁竭。上面 promise2 并不是 promise1菲茬,而是返回的一個(gè)新的 Promise 實(shí)例。
題目三
const promise = new Promise((resolve, reject) => {
resolve('success1')
reject('error')
resolve('success2')
})
promise
.then((res) => {
console.log('then: ', res)
})
.catch((err) => {
console.log('catch: ', err)
})
運(yùn)行結(jié)果:
then: success1
解釋:構(gòu)造函數(shù)中的 resolve 或 reject 只有第一次執(zhí)行有效派撕,多次調(diào)用沒(méi)有任何作用婉弹,呼應(yīng)代碼二結(jié)論:promise 狀態(tài)一旦改變則不能再變。
題目四
Promise.resolve(1)
.then((res) => {
console.log(res)
return 2
})
.catch((err) => {
return 3
})
.then((res) => {
console.log(res)
})
運(yùn)行結(jié)果:
1
2
解釋:promise 可以鏈?zhǔn)秸{(diào)用终吼。提起鏈?zhǔn)秸{(diào)用我們通常會(huì)想到通過(guò) return this 實(shí)現(xiàn)镀赌,不過(guò) Promise 并不是這樣實(shí)現(xiàn)的。promise 每次調(diào)用 .then 或者 .catch 都會(huì)返回一個(gè)新的 promise际跪,從而實(shí)現(xiàn)了鏈?zhǔn)秸{(diào)用商佛。
題目五
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('once')
resolve('success')
}, 1000)
})
const start = Date.now()
promise.then((res) => {
console.log(res, Date.now() - start)
})
promise.then((res) => {
console.log(res, Date.now() - start)
})
運(yùn)行結(jié)果:
once
success 1005
success 1007
解釋:promise 的 .then 或者 .catch 可以被調(diào)用多次,但這里 Promise 構(gòu)造函數(shù)只執(zhí)行一次垫卤⊥茫或者說(shuō) promise 內(nèi)部狀態(tài)一經(jīng)改變,并且有了一個(gè)值穴肘,那么后續(xù)每次調(diào)用 .then 或者 .catch 都會(huì)直接拿到該值歇盼。
題目六
Promise.resolve()
.then(() => {
return new Error('error!!!')
})
.then((res) => {
console.log('then: ', res)
})
.catch((err) => {
console.log('catch: ', err)
})
運(yùn)行結(jié)果:
then: Error: error!!!
at Promise.resolve.then (...)
at ...
解釋:.then 或者 .catch 中 return 一個(gè) error 對(duì)象并不會(huì)拋出錯(cuò)誤,所以不會(huì)被后續(xù)的 .catch 捕獲评抚,需要改成其中一種:
return Promise.reject(new Error('error!!!'))
throw new Error('error!!!')
因?yàn)榉祷厝我庖粋€(gè)非 promise 的值都會(huì)被包裹成 promise 對(duì)象豹缀,即 return new Error('error!!!') 等價(jià)于 return Promise.resolve(new Error('error!!!'))伯复。
題目七
const promise = Promise.resolve()
.then(() => {
return promise
})
promise.catch(console.error)
運(yùn)行結(jié)果:
TypeError: Chaining cycle detected for promise #<Promise>
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
at Function.Module.runMain (module.js:667:11)
at startup (bootstrap_node.js:187:16)
at bootstrap_node.js:607:3
解釋:.then 或 .catch 返回的值不能是 promise 本身,否則會(huì)造成死循環(huán)邢笙。類似于:
process.nextTick(function tick () {
console.log('tick')
process.nextTick(tick)
})
題目八
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
運(yùn)行結(jié)果:
1
解釋:.then 或者 .catch 的參數(shù)期望是函數(shù)啸如,傳入非函數(shù)則會(huì)發(fā)生值穿透。
題目九
Promise.resolve()
.then(function success (res) {
throw new Error('error')
}, function fail1 (e) {
console.error('fail1: ', e)
})
.catch(function fail2 (e) {
console.error('fail2: ', e)
})
運(yùn)行結(jié)果:
fail2: Error: error
at success (...)
at ...
解釋:.then 可以接收兩個(gè)參數(shù)氮惯,第一個(gè)是處理成功的函數(shù)叮雳,第二個(gè)是處理錯(cuò)誤的函數(shù)。.catch 是 .then 第二個(gè)參數(shù)的簡(jiǎn)便寫(xiě)法妇汗,但是它們用法上有一點(diǎn)需要注意:.then 的第二個(gè)處理錯(cuò)誤的函數(shù)捕獲不了第一個(gè)處理成功的函數(shù)拋出的錯(cuò)誤帘不,而后續(xù)的 .catch 可以捕獲之前的錯(cuò)誤。當(dāng)然以下代碼也可以:
Promise.resolve()
.then(function success1 (res) {
throw new Error('error')
}, function fail1 (e) {
console.error('fail1: ', e)
})
.then(function success2 (res) {
}, function fail2 (e) {
console.error('fail2: ', e)
})
題目十
process.nextTick(() => {
console.log('nextTick')
})
Promise.resolve()
.then(() => {
console.log('then')
})
setImmediate(() => {
console.log('setImmediate')
})
console.log('end')
運(yùn)行結(jié)果:
end
nextTick
then
setImmediate
解釋:process.nextTick 和 promise.then 都屬于 microtask杨箭,而 setImmediate 屬于 macrotask寞焙,在事件循環(huán)的 check 階段執(zhí)行。事件循環(huán)的每個(gè)階段(macrotask)之間都會(huì)執(zhí)行 microtask互婿,事件循環(huán)的開(kāi)始會(huì)先執(zhí)行一次 microtask捣郊。
******轉(zhuǎn)自******