Promise的使用
- promise最简单的使用方式:
const p1 = new Promise((resolve,reject) => {
console.log('创建一个Promise')
resolve('成功了')
//这里假设操作成功,
//resolve中的参数将作为.then的参数(成功的回调)
})
console.log('after new Promise')
const p2 = p1.then(
(data) => {
console.log(data)
throw new Error('失败了')
} //因为前面写的resolve,所以这里没写(err)=> {}
)
const p3 = p2.then(
(data) => {
console.log('success',data)
},
(err) => {
console.log('failed',err) //因为上一步抛出了错误,所以这里打印Error的信息
}
)
//控制台打印:
创建一个Promise
after new Promise
成功了
failed Error:失败了
-
默认情况下是等待状态pending,如果有一天状态转变为成功就成功了,如果状态变成失败就失败了,状态一旦改变了就不能再改变了。同时调用 resolve 函数和 reject 函数,默认会采取第一次调用的结果
-
上一个then不管走成功回调还是失败回调,只要返回一个普通值(非抛出错误,非返回Promise),就会走下一个的成功回调(参数是undefined),如果返回Promise,则由Promise来修改下一次的状态,从而觉得执行哪一个回调,成功or失败。
-
注意上面的executor函数体里写的是同步操作,如果是异步操作,.then时,Promise的状态仍是pedding
-
当执行.then时状态仍为pedding时,这时要把成功和失败的回调分别存在各自的队列里,等待请求结果回来后,在resolve或reject中执行(发布订阅)
-
手写实现的Promise里,使用 setTimeout 实现 promise 的异步。
-
由于原生的 Promise 是V8引擎提供的微任务,我们无法还原V8引擎的实现,所以这里使用 setTimeout 模拟异步,所以原生的是微任务,这里是宏任务。 @知乎 齐小神
手写promise
const resolvePromise = (promise2, x, resolve, reject) => {
// 自己等待自己完成是错误的实现,用一个类型错误,结束掉 promise Promise/A+ 2.3.1
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// Promise/A+ 2.3.3.3.3 只能调用一次
let called;
// 后续的条件要严格判断 保证代码能和别的库一起使用
if ((typeof x === 'object' && x != null) || typeof x === 'function') {
try {
// 为了判断 resolve 过的就不用再 reject 了(比如 reject 和 resolve 同时调用的时候) Promise/A+ 2.3.3.1
let then = x.then;
if (typeof then === 'function') {
// 不要写成 x.then,直接 then.call 就可以了 因为 x.then 会再次取值,Object.defineProperty Promise/A+ 2.3.3.3
then.call(x, y => { // 根据 promise 的状态决定是成功还是失败
if (called) return;
called = true;
// 递归解析的过程(因为可能 promise 中还有 promise) Promise/A+ 2.3.3.3.1
resolvePromise(promise2, y, resolve, reject);
}, r => {
// 只要失败就失败 Promise/A+ 2.3.3.3.2
if (called) return;
called = true;
reject(r);
});
} else {
// 如果 x.then 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.3.4
resolve(x);
}
} catch (e) {
// Promise/A+ 2.3.3.2
if (called) return;
called = true;
reject(e)
}
} else {
// 如果 x 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.4
resolve(x)
}
}
class myPromise {
constructor(executor){
this.state = 'pedding'
this.value = undefined
this.reason = undefined
this.onFullfilledList = []
this.onRejectedList = []
let resolve = (value) => {
if(this.state === 'pedding'){
this.state = 'success'
this.value = value
this.onFullfilledList.forEach(fn => fn())
}
}
let reject = (reason) => {
if(this.state === 'pedding'){
this.state = 'failed'
this.reason = reason
this.onRejectedList.forEach(fn => fn())
}
}
try {
executor(resolve,reject)
}catch(error){
reject(error)
}
}
then(onFullfilled,onRejected) {
onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : v => v
onRejected = typeof onRejected === 'function' ? onRejected : err => {throw err}
let promise2 = new Promise((resolve,reject) => {
if(this.state === 'success'){
setTimeout(()=>{
try {
let x = onFullfilled(this.value)
resolvePromise(promise2,x,resolve,reject)
}catch(err){
reject(err)
}
},0)
}
if(this.state === 'failed'){
setTimeout(()=>{
try{
let x = onRejected(this.reason)
resolvePromise(promise2,x,resolve,reject)
}catch(err){
reject(err)
}
},0)
}
if(this.state === 'pedding'){
this.onFullfilledList.push(()=>{
setTimeout(()=>{
try {
let x = onFullfilled(this.value)
resolvePromise(promise2,x,resolve,reject)
}catch(err){
reject(err)
}
},0)
})
this.onRejectedList.push(()=>{
setTimeout(()=>{
try{
let x = onRejected(this.reason)
resolvePromise(promise2,x,resolve,reject)
}catch(err){
reject(err)
}
},0)
})
}
})
return promise2
}
}
const resolvePromise = function(promise2,x,resolve,reject){
}
Promise Api
Promise.resolve() 返回一个成功的promise Promise.reject() 返回一个失败的promise Promise.all(arr) 都成功才成功,有一个失败则失败 Promise.race(arr) 取最快返回的结果的状态 Promise.prototype.catch((e)=>{}) 捕获错误,如果没有自己的失败处理函数,走catch
Promise.all
- 只有参数内所有的
promise
返回resolve
,才会返回resolve
- 参数中有一个失败
rejected
,就返回rejected
.原因是第一个失败rejected
的结果
Promise.all1 = function(arr){
if(!Array.isArray(arr)){
return new TypeError('err')
}
return new Promise((resolve,reject)=>{
let resArr = []
let count = 0
const processRes = (value,index) => {
resArr[index] = value
if(++count === arr.length){
resolve(resArr)
}
}
for(let i = 0; i < arr.length; i++){
if(arr[i] && typeof arr[i].then === 'function'){
arr[i].then((value)=>{
processRes(value,i)
},reject)
}else{
processRes(arr[i],i)
}
}
})
}
Promise.race
Promise.race = function(arr){
return new Promise((resolve,reject)=>{
for(let i = 0; i < arr.length; i++){
if(arr[i] && typeof arr[i].then === 'function'){
arr[i].then((value)=>{
resolve(value)
})
}else{
resolve(arr[i])
}
}
})
}
//这么简单得益于promise的状态只能改变一次,即resolve和reject都只被能执行一次
常见的问题:
- Promise解决了什么问题?(当然是回调地狱啦)
- Promise的实现有哪些?
- 常见的Api有哪些?
- 手写Promise?
- Promise在事件循环的执行过程是怎样的?
- Promise有什么缺陷,如何解决?
Q&A_1:Promise解决了什么问题?
- 异步请求的嵌套,后面的函数依赖前面函数的返回结果
- 多个异步请求并发,开发时往往需要同步请求最终的结果
解决:
- Promise链式调用解决回调地狱
- Promise.all获取多个任务的错误处理
new Promise()接受一个executor函数作为参数,在函数体里写要进行的请求,此函数会立即执行,并且拿到请求结果,修改Pedding状态,请求成功就改为成功状态,失败就为失败状态,然后用.then方法,拿到返回结果(成功的data和失败的err)
promise错误处理 Promise.reject(),直接将值变成错误结果 promise.prototype.catch,用来捕获promise异常,相当于一个没有成功的then promise。prototyoe.finally,finally表示无论如何都会执行,如果返回失败,会将其传到catch中