promise方法大全
前言
笔者之前写过相关的内容,但是讲的不够深入,这篇是更加综合的一个内容,结合网上的一些文章和例子,部分内容和例子引用:https://juejin.cn/post/7321996765977198611
promise
Promise是ES6异步编程的一种解决方案(目前最先进的解决方案是async和await的搭配(ES8),但是它们是基于promise的),从语法上讲,Promise是一个对象或者说是构造函数,用来封装异步操作并可以获取其成功或失败的结果。
为什么使用promise
1.可以避免多层异步调用嵌套问题(回调地狱)
2.Promise 对象提供了简洁的API,使得控制异步操作更加容易(js执行机制导致的异步问题)
promise的三种状态
1.pending: 等待中,或者进行中,表示还没有得到结果
2.resolved(Fulfilled): 已经完成,表示得到了我们想要的结果,可以继续往下执行
3.rejected: 也表示得到结果,但是由于结果并非我们所愿,因此拒绝执行
这三种状态不受外界影响,而且状态只能从pending改变为resolved或者rejected,并且不可逆
let p = new Promise((resolve, reject) => {
//状态改变是不可逆的,因此rejected改变后,后面的resolve就没用了
reject('error')
resolve("ok")
}).then(res => {
console.log(res,"1")
return ("ok2")
}).then(res => {
console.log(res,"2")
}).catch(err => {
// 直接穿透前面的then函数,执行catch函数
console.log(err,"3") //error
})
//输出 :error 3
promise的静态方法
resolve( )
Promise.resolve(value)
- value:成功的数据或 promise 对象
- resolve()返回一个成功或失败的 promise 对象(不改变原promise对象状态)
//如果传入的参数为 非 Promise 类型的对象,返回结果为成功 promise 对象
Promise.resolve("成功").then(
(value) => {
console.log(value); // "成功"
},
(reason) => {
console.log(reason)// 不会被调用
},
);
//如果传入的参数为 Promise 对象,则参数的结果决定了 resolve 的结果
Promise.resolve(new Promise((resolve, reject) => {
reject('error')
})).then(
(value) => {
console.log(value); // 不会被调用
},
(reason) => {
console.log(reason) //error,注意这里的reason是then的第二个参数,因此执行的是catch的作用
}
)
注意:多个resolve声明时,只有第一个声明成立
实现链式的调用:
前面任何操作出了异常,也都会传到最后失败的回调中处理
let p = new Promise((resolve, reject) => {
resolve("ok")
}).then(res => {
console.log(res,"1")
return ("ok2")
}).then(res => {
console.log(res,"2")
}).catch(err => {
// 直接穿透前面的then函数,执行catch函数
console.log(err,"3") //error
})
//输出 :ok 1
// ok2 2
reject( )
Promise.reject(reason)
- reason:失败的原因
- 返回一个失败的 promise 对象(快速得到一个 promise 对象,且永远是一个失败的 promise 对象)
//如果传入的参数为 非 Promise 类型的对象,返回结果为失败的 promise 对象
Promise.reject("失败").then(
(value) => {
console.log(value); // 不会被调用
},
(reason) => {
console.log(reason) // "失败"
},
);
当内部是promise对象
const p = Promise.reject(new Promise((resolve, reject) => {
resolve('ok')
}).then(res=>{
console.log(res,"3")
//3对应的是内部new出来的promise对象
})
)
//1对于的是p,他本身是一个promise,内部还包裹了一个promise
//catch返回的是promise.reject()内部的promise对象(此时他作为reject传递的对象),因此应该是fulfilled状态
//因为内部的promise对象返回的方法是resolve()
p.catch((res)=>{
console.log(res,"1")
})
//2就是输出p
//但是由于Promise.reject()直接把状态变成rejected状态,因此p永远是rejected
console.log(p,"2")

all( )
Promise.all()方法用于将多个 Promise实例,包装成一个新的 Promise实例
语法:
const p = Promise.all([p1, p2, p3])
接受一个数组(迭代对象)作为参数,数组成员都应为Promise实例
如果参数包含非 Promise 对象(即普通的值或非 Promise 对象),它们会被视为已经解决的 Promise,且会立即被视为成功
实例p的状态由p1、p2、p3决定,分为两种:
- 只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数
- 只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数
注意,如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法
例子1:正常返回
const p1 = Promise.resolve(3);
const p2 = 1337;
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("foo");
}, 100);
});
Promise.all([p1, p2, p3]).then((values) => {
console.log(values); // [3, 1337, "foo"]
});
例子2(p2没有自己的catch方法,就会调用Promise.all()的catch方法)
const p1 = new Promise((resolve, reject) => {
resolve('hello')
}).then((result) => result)
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了')
}).then((result) => result)
Promise.all([p1, p2])
.then((result) => console.log(result))
.catch((e) => console.log(e)) // Error: 报错了
例子3(返回值组成一个数组,传递给p的回调函数,参数promise对象自定义了catch方法)
//resolved状态
const p1 = new Promise((resolve, reject) => {
resolve('hello')
})
.then((result) => result)
.catch((e) => e)
//rejected状态
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了')
})
.then((result) => result)
.catch((e) => e)
//rejected状态
const p3 = new Promise((resolve, reject) => {
reject('me too')
})
.then((result) => result)
.catch((e) => e)
//由于p2,p3自身定义了catch方法
//因此all直接用他们自己的catch方法,并且从.then中输出
const p = Promise.all([p1, p2, p3])
.then((result) => console.log(result))
// ["hello", Error: 报错了 at file xxx,"me too"]
.catch((e) => console.log(e)) //不执行
race( )
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例
语法:
const p = Promise.race([p1, p2, p3])
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变率先改变的 Promise 实例的返回值则传递给p的回调函数
例子1
settimeout的格式
setTimeout(function, delay, arg1, arg2, ...);
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
const p = Promise.race([promise1, promise2])
setTimeout(() => {
console.log(p); //Promise {<fulfilled>: 'two'}
}, 1000);
allSettled( )
promise.allSettled()方法将一个 Promise 可迭代对象作为输入,并返回一个新的 Promise 实例
当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时,返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组
无论是fulfilled还是rejected状态都是传入对象数组中,所以都是直接使用.then即可
Promise.allSettled(iterable) //promise组成的可迭代对象,如数组
let p1=Promise.resolve(33)
let p2= new Promise((resolve) => setTimeout(() => resolve(66), 0))
let p3=99
let p4= Promise.reject(new Error("一个错误"))
let p=Promise.allSettled([p1,p2,p3,p4]).then(res=>{
console.log(res,"对象数组")
console.log(res[0].value,"索引为0的对象value")
console.log(res[0].status,"索引为0的对象类型")
console.log(res[3].reason,"索引为3的对象的报错")
})
console.log(p,"p")

throw抛出错误
- 正常情况下,在通过 throw() 关键字抛出错误时,JavaScript 运行时的错误处理机制会停止执行抛出错误之后的任何指令
throw Error('foo');
console.log('bar'); // 这一行不会执行
// Uncaught Error: foo
- 在 Promise 中抛出错误时,因为错误实际上是从消息队列中异步抛出的,所以并不会阻止运行时继续执行同步指令
Promise.reject(Error('foo'));
console.log('bar');
// bar
// Uncaught (in promise) Error: foo
//由此可知:异步错误只能通过异步的 onRejected 处理程序捕获
需要注意的是,try/catch仅能捕获同步代码中的错误,并不能捕获异步代码中的错误。对于异步代码,你可以使用.catch方法或async/await来捕获错误。
then()和 catch() 的 onRejected 处理程序在语义上相当于 try/catch。出发点都是捕获错误之后将其隔离,同时不影响正常逻辑执行
console.log('begin同步');
try {
throw Error('foo',"1");
console.log("hhh")//此行不会执行,因为上面throw了一个错误
} catch(e1) {
console.log('caught error', e1);
}
console.log('continuet同步');
new Promise((resolve, reject) => {
console.log('begin 异步');
reject(Error('bar',"2"));
}).catch((e) => {
console.log('caught error', e);
}).then(() => {
console.log('continue 异步');
});

promise的实例方法
①then()得到异步任务的正确结果
②catch()获取异常信息
注意:then方法可以接受两个参数,第一个参数为promise状态为成功的回调函数,第二个参数为promise状态为失败的回调函数(可以不写,一般用catch方法捕获promise状态为失败的异常信息)
let p = new Promise((resolve, reject) => {
reject('OK1')
})
p.then(null,res => {
console.log(res) //微任务先执行,后文有详细介绍
})
//此时的.then执行功能是.catch的功
//null顶替了第一个参数,第二个参数代表的就是rejected
function fn(flag) {
return new Promise(function(resolve, reject) {
if (flag === true) {
resolve('promise状态为成功!')
};
if (flag === false) {
reject('promise状态失败!')
};
}).then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
}
fn(true)
fn(false)
//多个resolve声明时,只有第一个声明成立
常见问题
1.一个 promise 指定多个成功/失败回调函数,都会调用吗?
当promise对象状态改变时,对应的成功/失败均会调用
//当promise改变为对象状态时都会调用
let p = new Promise((resolve, reject) => {
resolve('OK')
resolve("22")
})
p.then(res => {
console.log(res)
})
p.then(res => {
console.log(res)
})
//ok
//ok
反之,即使声明了多个resolve,也只会传递第一个resolve声明
2.改变 promise 状态 和执行回调函数谁先谁后?
let p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("宏任务执行")
//由于resolve声明在宏任务中
//因此.then回调本质也是等宏任务执行完了才有参数输出
resolve('ok')
},1000) //宏任务
})
p.then(res => {
console.log(res) //微任务
})
Promise.resolve("hhh").then(res=>{
console.log(res,"hhh")//微任务
})

3.promise 异常穿透
(1)当使用 promise 的 then 链式调用时,可以在最后指定失败的回调
(2)前面任何操作出了异常,都会传到最后失败的回调中处理
let p = new Promise((resolve, reject) => {
resolve(Error("cuo"),)
}).then(res => {
console.log(res)
}).catch(err => {
// 直接穿透前面的then函数,执行catch函数
console.log(err)
})

4.如何中断 promise 链?
- 在回调函数中返回一个 pendding 状态的 promise 对象(可能会造成内存泄露)
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
}, 1000)
}).then(res => {
console.log(res) //想在此处中断
return new Promise(() => { })
//返回 pendding 状态的 promise 的对象,中断!
}).then(res => {
console.log(res)
}).then(res => {
console.log(res)
})
- 直接通过throw抛出错误对象
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
}, 1000)
}).then(res => {
console.log(res) //想在此处中断
throw new Error('中断')
}).then(res => {
console.log('ok1')
}).then(res => {
console.log('ok2')
}).catch(error => {
console.log('catch error:', error)
})
- 使用reject
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
}, 1000)
}).then(res => {
console.log(res) //想在此处中断
//new一个新的promise之后,把他状态变为rejected,并且return出去
return Promise.reject('error here')
}).then(res => {
console.log('ok1')
}).then(res => {
console.log('ok2')
}).catch(error => {
console.log('catch error:', error)
})
更多推荐


所有评论(0)