一. Promise 是什么
1.1 Promise 理解
抽象表达
(1)Promise 是一门新的技术(ES6规范)
(2)Promise 是 JS 进行异步编程的新的解决方案(旧方案:使用回调函数)
具体表达 (1)语法上来讲 Promise 是一个构造函数 (2)功能上来说 Promise 对象可以封装一个异步操作,获取其结果值(成功/失败),并对结果进行处理
1.2 Promise 的状态改变
- pending 变成 resolved
- pending 变成 rejected
注:只有这两种,且一个 promise 对象只能改变一次,不论成功/失败,都会有一个结果数据
成功的结果一般称为 value,失败的结果一般称为 reason
Promise 的状态
实例对象中的一个属性 『PromiseState』
内置属性,不能直接对属性操作,结果值如下:
pending 未决定
resolved / fulfilled 成功
Rejected 失败
Promise 对象的值 实例对象中的另外一个属性 『PromiseResult』保存对象,成功/失败 的结果 如下两函数
resolve
reject
注:只有上面两个函数可以对实例对象中 PromiseResult 的值进行修改
let p = new Promise((resolve, reject) => {
// 成功的值
resolve('success')
// 失败的值
// reject('error')
})
1.3 Promise 的基本流程
二.为什么要用 Promise
2.1 指定回调函数更加灵活
旧方案:必须在启动异步任务前指定
新方案:启动异步任务 => 返回 Promise 对象 => 给回 promise对象绑定回调函数(可在异步任务结束后指定or多个)
2.2 支持链式调用,可以解决回调地狱问题
回调地狱: 回调函数嵌套使用,外部回调函数异步执行的结果是嵌套的回调函数的条件
回调函数的缺点:不便于阅读,不便于异常处理
promise 链式调用,可以解决回调地狱
三.如何使用 Promise
3.1 API
3.1.1 Promise 构造函数
new 实例化对象, Promeise(excutor){} (1)executor函数:执行器 (resolve, reject) => {} (2)resolve函数:内部定义,成功时调用的函数 value => {} (3)reject函数:内部定义,失败时调用的函数 reason => {} 注:executor 会在 Promise 内部立即同步调用,异步操作会在执行器中执行
// new Promise() 函数的参数被称为执行器函数,内部同步调用
let p = new Promise((resolve, reject) => {
console.log(1)
})
console.log(2)
3.1.2 Promise.prototype.then 方法
(onResolved, onRejected) => {} (1)onResolved 函数:成功的回调函数 (value) => {} (2)onRejected 函数:失败的回调函数 (reason) => {} 注:用于得到成功 value 的回调函数,用于得到失败 reason 的回调函数,都返回一个新的 promise 对象
3.1.3 Promise.prototype.catch 方法
(onRejected) => {} onRejected 函数:失败的回调函数 (reason) => {}
let p = new Promise((resolve, reject) => {
// 执行器函数中 执行reject
reject('error')
})
p.catch(reason => {
console.log(reason)
})
// 单独封装 内部也有由 then 方法实现的
3.1.4 Promise.resolve 方法
Promise 的函数对象,不属于实例对象
(value) => {} value:成功的数据 promise 对象
返回一个 成功/失败 的 promise 对象
// 1.传入参数为 非promise类型的对象,返回 成功状态的 promise 对象
let p1 = Promise.resolve('哈哈')
console.log(p1)
// 2.传入参数为 promise对象,参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
reject('error')
}))
console.log(p2)
3.1.5 Promise.reject
属于 Promise 函数对象,不属于实例对象
(reason) => {} reason:失败的原因,返回一个失败状态的 promise 对象
作用:快速返回一个失败的 promise 对象,失败的值,就是传递进来的值
let p = Promise.reject('666')
let p1 = Promise.reject(666)
let p2 = Promise.reject(new Promise((resolve, reject) => {
resolve('
resolve('success')
}))
// 始终返回一个失败的 promise 对象,失败的值,是传递进来的值
console.log(p, p1, p2)
3.1.6 Promise.all
属于 Promise 函数对象 (promise) => {} promises:包含 n个 promise 对象
注:返回一个新的 promise,只有所有的 promise 都成功才成功,有一个失败就失败
let p1 = new Promise((resolve, reject) => {
resolve('success')
})
let p2 = Promise.resolve('ok1')
let p3 = Promise.resolve('ok2')
// 三个都成功,是三个成功的结果值 数组
let result1 = Promise.all([p1, p2, p3])
console.log(result1)
let p4 = Promise.reject('失败1')
let p5= Promise.reject('失败2')
// 返回失败的 promise 对象值,且是第一个失败的值
const result2 = Promise.all([p1, p4 p5])
console.log(result2)
3.1.7 Promise.race
属于 Promise 函数对象 (promise) => {} promises:包含 n个 promise 对象 注:返回一个新的 promise,第一个完成的 promise 的结果状态就是最终结果的状态
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 100)
})
let p2 = Promise.resolve('ok')
let p3 = Promise.resolve('成功')
// 第一个完成的 promise 的结果状态就是最终的结果状态
const result = Promise.race([p1, p2, p3])
console.log(result)
3.2 promise 关键问题
3.2.1 promise 如何修改状态
(1)resolve(value) 如果当前是 pending,会变成 resolved
(2)reject(value) 如果当前是 pending,会变成 rejected
(3)抛出异常 如果当前是 pending,会变成 rejected
3.2.2 能否执行多个回调
当 promise 状态改变时,指定的多个成功/失败的回调函数,都会调用
let p = new Promise((resolve, reject) => {
// 状态改变,都会调用
resolve('success')
})
// 回调 1
p.then(value => { console.log(111) })
// 回调 2
p.then(value => { console.log(222) })
3.2.3 改变 Promise 状态、指定回调函数谁先执行
都有可能
情况一:先执行 resolve 改变状态,后执行回调函数
// 执行器函是任务是同步任务
let p = new Promise((resolve, reject) => {
resolve('success')
})
p.then(value => {
console.log(value)
}, reason => {})
情况二:then() 方法先执行,改变状态后执行(实际居多)
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000);
});
p.then(value => {
console.log(value)
}, reason => {});
1. 如何先改变状态,再指定回调函数
(1)执行器函数直接调用 resolve() / reject()
(2)延长更长时间再调用 then()
2. 什么时候得到数据(回调函数什么时候执行)
(1)先指定回调,状态发生改变时,回调函数就会调用,得到数据
(2)先改变状态,指定回调时,回调函数就会调用,得到数据
3.2.4 then() 方法返回的新的 promise 结果状态由什么决定
简单描述:由 thn() 指定的回调函数执行结果决定
详细描述:
(1)抛出异常,新 promise 状态变成 rejected
let p = new Promise((resolve, reject) => {
resolve('ok');
});
p.then(value => {
throw '404
}, reason => {})
(2)返回的是promise 的任意值,状态为 resolved,value 为返回值
(3)返回新 promise,此 promise的结果为新的 promise 结果
3.2.5 promise 如何串联多个操作任务
promise 的 then() 返回一个新的 promise(链式调用),可以实现
// 状态改变后,执行回调函数,在执行回调函数...
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000)
})
p.then(value => {
return new Promise((resolve, reject) => {
resolve('success')
}).then(value => {
// success
console.log('1 =>', value)
}).then(value => {
// undefind
// 状态由指定的回调函数返回值决定,状态没写,所以结果是undfind
console.log('2 =>', value)
})
})
3.2.6 promise 异常穿透
(1)使用 romise 的 then 链式调用时,可以在最后指定失败的回调
(2)前面任何操作出现异常,都会传递到最后失败的回调中处理
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
// reject('error')
}, 1000)
});
p.then(value => {
// console.log(111)
throw '失败了'
}).then(value => {
console.log(222)
}).then(value => {
console.log(333)
}).catch(reason => {
console.warn(reason)
})
3.2.7 中断 promise 链
有且只有一种方式:return 一个 pending 状态的 promise 对象
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
// reject('error')
}, 1000)
});
p.then(value => {
console.log(111)
// 返回 pending 状态 promise
return new Promise(() => {})
}).then(value => {
console.log(222)
}).then(value => {
console.log(333)
}).catch(reason => {
console.warn(reason)
})