一、promise相关概念
回调方法:就是将一个方法 func2 作为参数传入另一个方法 func1 中,当 func1 执行到某一步或者满足某种条件的时候才执行传入的参数 func2
Promise 是 ES6 引入的异步编程的新解决方案。
Promise 对象三种状态:初始化、成功、失败 pending-进行中、resolved-已完成、rejected-已失败
就好像,你跟你女朋友求婚,她跟你说她要考虑一下,明天才能给你答案,这就是承诺(promise)。同时,这也是一个等待的过程(pending),然后你就等,等到明天你女朋友给你答复,同意(resolved)或者拒绝(rejected),如果同意就准备结婚了,如果不同意就等下次再求婚,哈哈哈。
promise 是用来解决两个问题的:
- 回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象
- promise 可以支持多个并发的请求,获取并发请求中的数据
- 这个 promise 可以解决异步的问题,本身不能说 promise 是异步的
二、promise基本用法
这样构造 promise 实例,然后调用 .then.then.then 的编写代码方式,就是 promise。
let p = new Promise((resolve, reject) => { // 调用了Promise构造函数
// 做一些事情
// 然后在某些条件下resolve,或者reject
if (/* 条件随便写^_^ */) {
resolve()
} else {
reject()
}
})
p.then(() => { // 调用了promise实例的.then方法
// 如果p的状态被resolve了,就进入这里
}, () => {
// 如果p的状态被reject
})
三、声明一个promise对象
new Promise((resolve, reject) => { // 这两个方法主要是用来修改状态的
console.log("开始求婚。")
console.log("。。。。。")
console.log("考虑一下。")
setTimeout(() => {
if (isHandsome || isRich) { // 当我们调用 resolve 函数的时候,Promise 的状态就变成 resolved
resolve('我同意!')
} else { // 当我们调用 reject 函数的时候,Promise 的状态就变成 reject
reject("拒绝:我们八字不合")
}
}, 2000)
})
// 如果一个 promise 已经被兑现(resolved)或被拒绝(rejected),那么我们也可以说它处于已敲定(settled)状态。
四、Promise.prototype.then 方法
已成功 resolved 的回调和已失败 rejected 的回调
// 调用 Promise 对象的then方法,两个参数为函数
p.then(function(value){ // 成功
console.log(value);
}, function(season){ // 失败
console.log(season);
});
五、Promise.prototype.catch 方法
catch() 的作用是捕获 Promise 的错误
其实它和 then 的第二个参数一样,用来指定 reject 的回调,用法是这样:
在执行 resolve 的回调(也就是上面 then 中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死 js,而是会进到这个 catch 方法中。请看下面的代码:
promise.then(
() => { console.log('this is success callback') }
).catch(
(err) => { console.log(err) }
)
效果和写在 then 的第二个参数里面一样。不过它还有另外一个作用:在执行 resolve 的回调(也就是上面 then 中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死 js ,而是会进到这个 catch 方法中。请看下面的代码:
getNumber()
.then(function(data){
console.log('resolved');
console.log(data);
console.log(somedata); //此处的somedata未定义
})
.catch(function(reason){
console.log('rejected');
console.log(reason);
});
六、Promise.all() 方法
- 有了 all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据。
- 「谁跑的慢,以谁为准执行回调」
- Promise 的 all 方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调
Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});
Promise.all 手撕代码题:
const myPromiseAll =(arr)=>{
let result = [];
return new Peomise ((resolve,reject)=>{
for (let i=0;i<arr.length;i++){
arr[i].then(data=>{
result[i] = data;
if(result.length === arr.length)//所有的都成功才执行成功的回调
{
resolve(result)
}//这里可以用计数器更好点
},reject)//有一个失败则执行失败的回调
}
})
}
七、Promise.race() 方法
- 「谁跑的快,以谁为准执行回调」
- 1 秒后 runAsync1 已经执行完了,此时then里面的就执行了
- 在 then 里面的回调开始执行时,runAsync2() 和 runAsync3() 并没有停止,仍旧再执行。
- 于是再过 1 秒后,输出了他们结束的标志。
//请求某个图片资源
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx';
});
return p;
}
//延时函数,用于给请求计时
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('图片请求超时');
}, 5000);
});
return p;
}
Promise
.race([requestImg(), timeout()])
.then(function(results){
console.log(results);
})
.catch(function(reason){
console.log(reason);
});
八、Promise.any() 方法
any() 方法还接受一组 promise 作为参数,并将它们打包到新的 promise 对象中。只要一个参数实例处于成功状态,新的 promise 就处于成功状态。参数实例均处于拒绝状态。新承诺处于拒绝状态。
Promise.any(promises).then(
(first) => {
// Any of the promises was fulfilled.
},(error) => {
// All of the promises were rejected.
}
);
Promise.any手撕代码题:
function myPromiseAny(arr) {
if (!Array.isArray(arr)) {
throw new Error('arguments must be a array');
}
let rejectCount = 0;
return new Promise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
arr[i].then(data => {
resolve(data);
}, () => {
rejectCount++;
if (rejectCount === arr.length) {
reject(new AggregateError('All promises were rejected'))
}
});
}
})
}
九、Promise.prototype.finally() 方法
finally 方法用于指定无论 Promise 对象的最终状态如何,都将执行 finally。Finally 不接受参数。Finally 独立于先前的执行状态,不依赖于先前的运行结果。
const promise4 = new Promise((resolve, reject) => {
console.log(x + 1);
});
promise4
.then(() => {
console.log("你好");}
).catch((err) => {
console.log(err);}
).finally(() => {
console.log("finally");});// finally