Open liangbus opened 5 years ago
new Promise(() => {
throw Error('something happended!')
}).catch(err => {
console.log(`err > `, err)
}).then(() => {
console.log(`I am in then func`)
})
// 执行结果
err > Error: something happended!
at <anonymous>:2:8
at new Promise (<anonymous>)
at <anonymous>:1:1
VM425:6 I am in then func
Promise {<resolved>: undefined}
这是有一次面试遇到的一个问题,感觉这么问,结果大概率是会执行的,但是并不知道为什么[cry]
从结果导向,既然执行了 then ,那就看执行完 catch 方法后,返回是什么就知道了
new Promise(() => {
throw Error('something happended!')
}).catch(err => {
console.log(`err > `, err)
})
VM536:4 err > Error: something happended!
at <anonymous>:2:8
at new Promise (<anonymous>)
at <anonymous>:1:1
Promise {<resolved>: undefined}
注意这里返回结果是一个 Promise ,并且其状态是 resolved !!
仅执行构造函数,返回结果如下
new Promise(() => {
throw Error('something happended!')
})
Promise {<rejected>: Error: something happended!
at <anonymous>:2:8
at new Promise (<anonymous>)
at <anonymo…}
状态为 rejected 的 Promise
MDN 的解释是这样子的
pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。
至此,该问题就很清晰了
参考: Promise - MDN
下面的代码输出什么?
Promise.resolve(1).then((res) => {
console.log('then >> ', res)
throw new Error('Wrong!!!!')
return 2
}).catch((err) => {
console.log('Error >> ', err)
return 3
}).then((res) => {
console.log('last then >>> ', res)
})
then >> 1
VM8925:6 Error >> Error: Wrong!!!!
at <anonymous>:3:8
VM8925:9 last then >>> 3
MDN 关于 Promise.resolve(value) 的描述
返回一个状态由给定value决定的Promise对象。如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(该value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法。通常而言,如果你不知道一个值是否是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value以Promise对象形式使用。
问题延伸
以下代码
Promise.resolve().then(() => {
console.log('inside then~')
return new Error('something WRONG!!')
}).then(res => {
console.log('inside second then ~', res)
}).catch(err => {
console.log('inside catch >> ', err)
})
VM260:2 inside then~
VM260:5 inside second then ~ Error: something WRONG!!
at <anonymous>:3:9
Promise {<resolved>: undefined}
注意这里并不是 throw Error 而是 return Error 因为返回任意一个非 promise 的值都会被包裹成 promise 对象,即 return new Error('error!!!') 等价于 return Promise.resolve(new Error('error!!!'))。 正确触发 catch 的写法:
return Promise.reject(new Error('error!!!'))
throw new Error('error!!!')
再来看下面代码
Promise.resolve()
.then(function success (res) {
throw new Error('error')
}, function fail1 (err) {
console.error('fail in reject func: ', err)
})
.catch(function fail2 (err) {
console.error('fail in catch: ', err)
})
VM10390:8 fail in catch: Error: error
at success (<anonymous>:3:11)
Promise {<resolved>: undefined}
可以看出 then 方法中传入的 reject 方法没办法捕获到 resovlve 中抛出的异常,只能由后续的 catch 方法捕获到 再来修改一下看看
Promise.resolve()
.then(function success (res) {
throw new Error('error')
}, function fail1 (err) {
console.error('fail in reject func: ', err)
}).then( function success2 (res) {
console.log('succeed in second success func', res)
}, function fail2 (err) {
console.error('fail in second reject func', err)
})
fail in second reject func Error: error
at success (<anonymous>:3:11)
Promise {<resolved>: undefined}
此时第一个 then 中抛出的异常,被第二个 then 中的 reject 方法捕获到了 其实原因还是因为 then 执行完之后,返回的 Promise 状态是 rejected,所以导致后面触发的是 reject 方法,同级的 reject 方法无法捕获同级的 resolve 中的异常,这也是 Promise 的局限性之一,也就叫做被吃掉的异常,因为总会有可能存在无法捕获的异常
练习:用 Promise 实现红绿灯问题 红灯三秒亮一次,绿灯一秒亮一次,黄灯2秒亮一次;如何让三个灯不断交替重复亮灯?
function red(){
console.log('red');
}
function green(){
console.log('green');
}
function yellow(){
console.log('yellow');
}
function lightup(t, fn) {
return new Promise((resolve, reject) => {
setTimeout(() => {
fn()
resolve()
}, t)
})
}
function round() {
Promise.resolve().then(() => {
return lightup(3000, red)
})
.then(() => {
return lightup(1000, green)
})
.then(() => {
return lightup(2000, yellow)
})
.then(() => {
round()
})
}
采用递归 + setTimeout 方式调用
最后附上简单版本的 Promise/A+ 手写实现
哥哥 你看我这个还有的救吗?除了开头那6秒多等,我想clearinterval当第一次执行时不等待,貌似不行。呜呜呜。。。。。。 function red() { console.log('red'); } function green() { console.log('green'); } function yellow() { console.log('yellow'); } let i = 0 setInterval(() => { if (i === 0) { clearInterval() } setTimeout(() => { red() setTimeout(() => { green() setTimeout(() => { yellow() }, 1000); }, 2000); }, 3000); i++ }, 6000);
基础知识点就不过多描述了,主要还是通过问题去发掘一些知识点
1. 关于 Promise 状态的理解
以下代码输出什么
resolve 完之后的代码也会执行,但是 resove 之后,Promise 的状态已从 pending 改为 resolved,关于状态的转换,Promise 的 A+ 规范上面有相应描述
即状态一旦更改,即不可逆,也不可变 所以即使 reject 了也不会进入 catch 方法
题目拓展 >>