Promise大家一定很熟悉吧。想一想,就那么几个API,但是你真的了解Promise吗?本文根据Promise的一些知识点总结了十道题,看看你能答对几题。以下promise指的是Promise实例,环境为Node.js。话题一constpromise=newPromise((resolve,reject)=>{console.log(1)resolve()console.log(2)})promise.then(()=>{console.log(3)})console.log(4)运行结果:1243解释:同步执行Promise构造函数,异步执行promise.then中的函数。题目二constpromise1=newPromise((resolve,reject)=>{setTimeout(()=>{resolve('success')},1000)})constpromise2=promise1.then(()=>{thrownewError('error!!!')})console.log('promise1',promise1)console.log('promise2',promise2)setTimeout(()=>{console.log('promise1',promise1)console.log('promise2',promise2)},2000)运行结果:promise1Promise{}promise2Promise{}(node:50928)UnhandledPromiseRejectionWarning:Unhandledpromiserejection(rejectionid:1):Error:error!!!(node:50928)[DEP0018]DeprecationWarning:未处理的承诺拒绝已弃用。将来,未处理的承诺拒绝将以非零退出代码终止Node.js进程。promise1Promise{'success'}promise2Promise{Error:error!!!atpromise.then(...)at}解释:promise有3种状态:pending、fulfilled或rejected。状态改变只能是pending->fulfilled或者pending->rejected,状态一旦改变,就不能再改变。上面的Promise2不是promise1,而是返回了一个新的Promise实例。\主题3constpromise=newPromise((resolve,reject)=>{resolve('success1')reject('error')resolve('success2')})promise.then((res)=>{console.log('then:',res)}).catch((err)=>{console.log('catch:',err)})运行结果:then:success1解释:构造函数中的resolve或reject只是第一个一次执行有效,多次调用无效,呼应代码2的结论:promise状态一旦改变,就无法再改变。主题4**Promise.resolve(1).then((res)=>{console.log(res)return2}).catch((err)=>{return3}).then((res)=>{console.log(res)})运行结果:12说明:promise可以链式调用。提到链式调用,我们通常会想到实现returnthis,但是Promise并不是这样实现的。每次promise调用.then或.catch时,都会返回一个新的promise,从而实现链式调用。主题5constpromise=newPromise((resolve,reject)=>{setTimeout(()=>{console.log('once')resolve('success')},1000)})conststart=Date.now()promise.then((res)=>{console.log(res,Date.now()-开始)})promise.then((res)=>{console.log(res,Date.now()-开始))})运行结果:oncesuccess1005success1007解释:promise的.then或.catch可以调用多次,但这里的Promise构造函数只执行一次。也就是说,一旦promise的内部状态发生了变化,有了值,那么后续每次调用.then或.catch都会直接得到这个值。主题6Promise.resolve().then(()=>{returnnewError('error!!!')}).then((res)=>{console.log('then:',res)}).catch((err)=>{console.log('catch:',err)})运行结果:then:Error:error!!!atPromise.resolve.then(...)at...引用解释:在.then或.catch中返回错误对象不会抛出错误,因此不会被后续的.catch捕获。它需要更改为其中之一:returnPromise.reject(newError('error!!!'))thrownewError('error!!!')reference因为返回任何非承诺值将被包装到一个promise对象,即returnnewError('error!!!')等同于returnPromise.resolve(newError('error!!!'))。引用主题7constpromise=Promise.resolve().then(()=>{returnpromise})promise.catch(console.error)result:TypeError:Chainingcycledetectedforpromise#atatprocess._tickCallback(internal/process/next_tick.js:188:7)atFunction.Module.runMain(module.js:667:11)atstartup(bootstrap_node.js:187:16)atbootstrap_node.js:607:3说明:.then或.catch返回的值不能是promise本身,否则会造成死循环。类似:process.nextTick(functiontick(){console.log('tick')process.nextTick(tick)})话题八Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)运行结果:1说明:.then或.catch的参数应该是一个函数,传入一个非函数会发生值穿透。题目9Promise.resolve().then(functionsuccess(res){thrownewError('error')},functionfail1(e){console.error('fail1:',e)}).catch(functionfail2(e){console.error('fail2:',e)})运行结果:fail2:Error:erroratsuccess(...)at...解释:.then可以接收两个参数,第一个是处理成功的函数,第二个是处理错误的函数。.catch是.then的第二个参数的一种写法,但是它们的用法有一点需要注意:.then的第二个错误处理函数无法捕捉到第一个处理成功的函数抛出的错误,后面的.catch可以捕获之前的错误。当然,下面的代码也可以:Promise.resolve().then(functionsuccess1(res){thrownewError('error')},functionfail1(e){console.error('fail1:',e)})。then(functionsuccess2(res){},functionfail2(e){console.error('fail2:',e)})Process.nextTick(()=>{console.log('nextTick')})承诺。resolve().then(()=>{console.log('then')})setImmediate(()=>{console.log('setImmediate')})console.log('end')结果:endnextTickthensetImmediate参考说明:process.nextTick和promise.then都属于microtask,setImmediate属于macrotask,在事件循环的check阶段执行。在事件循环的每个阶段(宏任务)之间执行一个微任务,在事件循环的开始执行一个微任务。引用