Promise的概念
Promise对象用于表示一个异步操作的最终状态(完成或失败)以及其返回的值 --- MDN
回调与Promise
模拟场景
实现一个功能:以1秒的间隔依次显示1,2,3,4
传统回调
// 方式1:传统回调方式
function f(cb) {
setTimeout(function () {
cb && cb();
}, 1000);
}
f(function () {
// 第一层回调中的处理
console.log(1);
f(function () {
// 第二层回调中的处理
console.log(2);
f(function () {
// 第三层回调中的处理
console.log(3);
f(function () {
// 第四层回调中的处理
console.log(4);
});
});
});
});
// 执行结果:以1秒的间隔依次显示1,2,3,4
这里只是举个例子,所有每一次层的处理都很简单,只是显示一个数字。
在实际业务中,每一次层的处理会很复杂。然后如果有需求想要交换下第二层和第三层的处理,该怎么弄?即使对业务逻辑很清楚,这事情处理起来也简直就是地狱。。甚至如果还有5678层呢?
Promise
// 方式2:Promise方式
function f(cb) {
// 说明
// 返回一个Promise实例
// 参数resolve代表成功时候要做的事情
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
}
// 说明
// 由于f返回的是一个Promise实例,所以拥有then方法
// then方法里就是实际要做的事情
f()
.then(() => {
console.log(1);
return f(); // 这里需要返回f(),这样就能继续then下去了
})
.then(() => {
console.log(2);
return f(); // 这里需要返回f(),这样就能继续then下去了
})
.then(() => {
console.log(3);
return f(); // 这里需要返回f(),这样就能继续then下去了
})
.then(() => {
console.log(4);
})
// 执行结果:以1秒的间隔依次显示1,2,3,4
// 这和传统回调方式的结果是一样的
可以看到,以Promise的方式处理这个问题,不是一层嵌一层的样子了,而是一步做完再接着做下一步。是不是比传统的回调方式好理解很多?交换某两个处理的顺序也会很方便。
新事物的出现一定有它的理由和好处,Promise就是为了解决回调地狱而出现的。非常友好,值得我们拥抱它。
错误处理
then(resolve, reject)
// then方法中的第二个回调reject,就是失败时候做的事情
function f(a) {
return new Promise((resolve, reject) => {
if (a) {
resolve();
} else {
reject();
}
})
}
f(false)
.then(() => {
console.log('我是成功时候的处理');
}, () => {
console.log('我是失败时候的处理');
});
// 执行结果:我是失败时候的处理
catch
// 使用实例的catch方法,可以捕获错误
function f(a) {
return new Promise((resolve, reject) => {
if (a) {
resolve();
} else {
reject();
}
})
}
f(false)
.then(() => {
// 这里不会执行到
console.log('我是成功时候的处理');
return f(false);
})
.catch(()=>{
console.log('我是失败时候的处理');
});
// 执行结果:我是失败时候的处理
finally
// 不伦成功还是失败,finally中的内容一定会执行
// 跟最终的处理一起执行
function f(a) {
return new Promise((resolve, reject) => {
if (a) {
resolve();
} else {
reject();
}
})
}
f(false)
.then(() => {
// 这里不会执行到
console.log('我是成功时候的处理');
return f(false);
})
.catch(() => {
console.log('我是失败时候的处理');
return f(true);
})
.finally(() => {
console.log('finally');
});
// 执行结果:我是失败时候的处理 finally
Promise的三种状态
- pending(进行中)
- fulfilled(成功)
- rejected(失败)
状态的改变不可逆,一旦决议就不能再修改。且只有以下两种改变形式。
pending(进行中) => fulfilled(成功)
pending(进行中) => rejected(失败)
Promise方法
Promise.all()
Promise.all方法可以把多个promise实例,包装成一个新的promise实例。
Promise.all([promise1,promise2,promise3]):Promise
特点1:当promise1,promise2,promise3都成功的时候,Promise.all就决议为成功,且返回由promise1/promise2/promise3的结果组成的数组。
// 模拟需要多个请求的数据,才能进行下一步操作的情况
function getData1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第一条数据加载成功!');
resolve('data1');
}, 1000);
});
}
function getData2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第二条数据加载成功!');
resolve('data2');
}, 1000);
});
}
function getData3() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第三条数据加载成功!');
resolve('data3');
}, 2000);
});
}
let p = Promise.all([getData1(), getData2(), getData3()]);
p.then(arr => {
console.log(arr);
});
// 执行结果:
// 1s之后显示:"第一条数据加载成功!" 和 "第二条数据加载成功!"
// 2s之后显示:"第三条数据加载成功!"
// p.then中的arr为 ["data1", "data2", "data3"]
特点2:当promise1,promise2,promise3之中有一个失败的时候,Promise.all就决议为失败,且返回失败的信息。
// 模拟需要多个请求的数据,才能进行下一步操作的情况
function getData1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第一条数据加载成功!');
resolve('data1');
}, 1000);
});
}
function getData2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第二条数据加载成功!');
resolve('data2');
}, 1000);
});
}
function getData3() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第三条数据加载失败!');
reject('err data3'); // !!注意这里调用的是reject,表示失败
}, 2000);
});
}
let p = Promise.all([getData1(), getData2(), getData3()]);
p
.then(arr => {
// 这里永远不会执行到
console.log(arr);
})
.catch(err => {
console.log(err);
});
// 执行结果:
// 1s之后显示:"第一条数据加载成功!" 和 "第二条数据加载成功!"
// 2s之后显示:"第三条数据加载失败!"
// p.catch中的err为 "err data3"
特点3:当Promise.all([])的时候,Promise.all就直接决议为成功。
let p = Promise.all([]);
p
.then(arr => {
console.log("成功");
})
.catch(err => {
console.log("失败");
});
// 执行结果:成功
Promise.race()
顾名思义,race是竞赛的意思。
所以Promise.race方法,是把多个promise实例中,最先成功或失败的结果拿出来。
Promise.race([promise1,promise2,promise3]):Promise
- 成功的情况
function getData1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第一条数据加载成功!');
resolve('data1');
}, 1000);
});
}
function getData2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第二条数据加载成功!');
resolve('data2');
}, 1500);
});
}
function getData3() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第三条数据加载成功!');
resolve('data3');
}, 500);
});
}
let p = Promise.race([getData1(), getData2(), getData3()]);
p.then(data => {
console.log(data); // data3
});
// 执行结果:
// 0.5s之后显示:"第三条数据加载成功!"
// p.then中的data为 "data3"
// 1s之后显示:"第一条数据加载成功!"
// 1.5s之后显示:"第二条数据加载成功!"
- 失败的情况
function getData1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第一条数据加载成功!');
resolve('data1');
}, 1000);
});
}
function getData2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第二条数据加载成功!');
resolve('data2');
}, 1500);
});
}
function getData3() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第三条数据加载失败!');
reject('err data3');
}, 500);
});
}
let p = Promise.race([getData1(), getData2(), getData3()]);
p.then(data => {
// 这里不会被执行到
console.log(data);
}).catch(data => {
console.log(data); // err data3
});
// 执行结果:
// 0.5s之后显示:"第三条数据加载失败!"
// p.then中的data为 "err data3"
// 1s之后显示:"第一条数据加载成功!"
// 1.5s之后显示:"第二条数据加载成功!"
Promise.resolve()
常用来生成已经被决议为成功的Promise实例
function f(a) {
return new Promise((resolve, reject) => {
if (a) {
resolve();
} else {
reject();
}
})
}
f(true)
.then(() => {
console.log('处理1');
return Promise.resolve(); // 这里就相当于 return f(true);
})
.then(() => {
console.log('处理2');
})
.catch(() => {
console.log('错误');
});
// 执行结果:处理1 处理2
Promise.reject()
常用来生成已经被决议为失败的Promise实例
function f(a) {
return new Promise((resolve, reject) => {
if (a) {
resolve();
} else {
reject();
}
})
}
f(true)
.then(() => {
console.log('处理1');
return Promise.reject(); // 这里就相当于 return f(false)
})
.then(() => {
console.log('处理2');
})
.catch(() => {
console.log('错误');
});
// 执行结果:处理1 错误