零、前言与重点难点
难点:2 5 6 7 8 10
重点:在 .then、.catch中 return 某数据类型(如 return {name: 'cyb', age: 22}),会自动包装成 return Promise.resolve({name: 'cyb', age: 22})。“从而流向后面的 .then !!!”
1、
const promise = new Promise((resolve, reject) => {
console.log(1)
resolve()
console.log(2)
})
promise.then(() => {
console.log(3)
})
console.log(4)
输出:1 2 4 3 。执行器也是同步的代码,.then方法是异步执行的。
2、
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)
输出:
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 种状态:pending、fulfilled 或 rejected。状态改变只能是 pending->fulfilled 或者 pending->rejected,状态一旦改变则不能再变。上面 promise2 !=== promise1,它是一个全新的 Promise 实例。
3、!!
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)
})
输出:then: success1 。Promise实力对象的执行器若有多个 reject、resolve 函数,!!仅第一个有效 ===> 对应 状态一旦发生改变就不能再变了,不可逆!!!
4、
Promise.resolve(1)
.then((res) => {
console.log(res)
return {name: 'sss',age: 2};
})
.catch((err) => {
return 3
})
.then((res) => {
console.log(res)
})
输出:1 {name: "sss", age: 2} 。promise 可以链式调用。一般链式调用都是通过 return this 实现的,但是 .then 或 .catch 的调用都会返回一个全新的 Promise(通过 return 语句,后面可以接 基本数据类型和复杂数据类型!如 return {name: "sss", age: 2} 或 return new Error('错误'),然后分别在 后面的 then、catch中获取 )。
补充:Promise.resolve('成功数据')、Promise.reject('错误原因')可以直接快速生成Promise对象; 分别在后面的 then、catch 中拿到相应的数据或错误原因等!!
5、
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)
})
输出:once success 1004 success 1004。
promise的 .then、 .catch 可以多次被调用(但是拿到的值都是一样的!!如上面的 success 。),但是执行器只会执行一遍!!promise内部状态一经改变,并且有了一个值,那么后面即使再调用 .then、.catch 还是会拿到这个值!!!
6、
Promise.resolve()
.then(() => {
return new Error('error!!!')
})
.then((res) => {
console.log('then: ', res)
})
.catch((err) => {
console.log('catch: ', err)
})
输出:then: Error: error!!!
.then、.catch中 return 一个 error 对象并不会抛出错误(相当于返回一个带有“错误原因”的Promise对象,对应后面的resolve,而不是catch!!!),不会被后面的 catch 捕获到。想要被 catch ,可以改成 throw new Error(‘错误’) 抛出错误 或者 return Promise.reject(new Error('错误')) 生成一个“带错误”的Promise新实例对象。
因为返回任意一个非 promise 的值都会被包裹成 promise 对象(“通过resolve去包裹,所以不会走向 .catch!!”),即 return new Error('error!!!')
等价于 return Promise.resolve(new Error('error!!!'))
。
7、
const promise = Promise.resolve()
.then(() => {
return promise
})
promise.catch(console.error)
输出:会造成死循环!!
.then、.catch本身不能 return promise实力对象自身,会造成死循环。如:
process.nextTick(function tick () {
console.log('tick')
process.nextTick(tick)
})
8、
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
输出:1
.then、.catch 都期望传入函数,如果传入 非函数, 会发生 值穿透(自上而下的值穿透) !!!感觉上面的写法“等同”于下面(目前输出结果一致):
Promise.resolve(1)
.then(data => data)
.then(d => d)
.then(d => console.log(d))
9、
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)
})
输出: fail2: Error: error 。
比较好理解。总之,“只能捕获上一级抛出的错误”。
.then
可以接收两个参数,第一个是处理成功的函数,第二个是处理错误的函数。.catch
是 .then
第二个参数的简便写法,但是它们用法上有一点需要注意:.then
的第二个处理错误的函数捕获不了第一个处理成功的函数抛出的错误,而后续的 .catch
可以捕获之前的错误。
10、
process.nextTick(() => {
console.log('nextTick')
})
Promise.resolve()
.then(() => {
console.log('then')
})
setImmediate(() => {
console.log('setImmediate')
})
console.log('end')
输出:end nextTick then setImmediate
process.nextTick
和 promise.then
都属于 microtask,而 setImmediate
属于 macrotask,在事件循环的 check 阶段执行。事件循环的每个阶段(macrotask)之间都会执行 microtask,事件循环的开始会先执行一次 microtask。