1.Promise简介
1.1 Promise是什么
- 抽象表达:Promise是JS中进行异步编程的新的解决方案(旧方案是单纯使用回调函数)
- 具体表达: ①从语法上看:Promise是一个构造函数 (自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法) ②从功能上看:promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
- 阮一峰的解释: 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果 从语法上说,Promise 是一个对象,从它可以获取异步操作的消息 Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理
Promise 的状态: 实例对象promise中的一个属性 PromiseState pending 变为 resolved/fullfilled pending 变为 rejected 注意: 对象的状态不受外界影响 只有这两种,且一个 promise 对象只能改变一次 一旦状态改变,就不会再变,任何时候都可以得到这个结果 无论成功还是失败,都会有一个结果数据。成功的结果数据一般称为 value,而失败的一般称为 reason。
1.2 Promise基本使用
流程:
基本使用:
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(reason);
}
});
1.3 为什么使用Promise
-
指定回调函数的方式更加灵活 旧的:必须在启动异步任务前指定
-
支持链式调用,可以解决回调地狱问题 回到地狱:回调函数嵌套调用,外部回调函数异步执行的结果是其内部嵌套的回调函数执行的条件 回调函数缺点:不便于阅读、不便于异常处理 解决回调地狱的方案:
-
Promise链式调用
-
async/await
1.4 中断Promise链
我们都知道promise状态一旦变为resolve或reject就不会再改变,中间无法中断,那如何中断链式调用呢? 当使用 promise 的 then 链式调用时,在中间中断,不再调用后面的回调函数 办法:在回调函数中返回一个 pending 状态的 promise 对象
new Promise((resolve, reject) => {
//resolve(1)
reject(1)
}).then(
value => {
console.log('onResolved1()', value)
return 2
}
).then(
value => {
console.log('onResolved2()', value)
return 3
}
).then(
value => {
console.log('onResolved3()', value)
}
).catch(
reason => {
console.log('onRejected1()', reason)
}
).then(
value => {
console.log('onResolved4()', value)
},
reason => {
console.log('onRejected2()', reason)
}
)
// onRejected1() 1
// onResolved4() undefined
为了在 catch 中就中断执行,可以这样写:
new Promise((resolve, reject) => {
//resolve(1)
reject(1)
}).then(
value => {
console.log('onResolved1()', value)
return 2
}
).then(
value => {
console.log('onResolved2()', value)
return 3
}
).then(
value => {
console.log('onResolved3()', value)
}
).catch(
reason => {
console.log('onRejected1()', reason)
return new Promise(() => {}) // 返回一个pending的promise
}
).then(
value => {
console.log('onResolved4()', value)
},
reason => {
console.log('onRejected2()', reason)
}
)
// onRejected1() 1
在 catch 中返回一个新的 promise,且这个 promise 没有结果。 由于,返回的新的 promise 结果决定了后面 then 中的结果,所以后面的 then 中也没有结果。 这就实现了中断 promise链的效果。
2.Promise顺序请求
方法1——连续使用then链式调用 方法2——使用promise构建队列 方法3——使用async、await实现类似同步编程,async函数内部实现同步 参考:www.jianshu.com/p/dbda3053d…
方法1:链式调用
function getA(){
return new Promise(function(resolve, reject){
setTimeout(function(){
resolve(2);
}, 1000);
});
}
function getB(){
return new Promise(function(resolve, reject){
setTimeout(function(){
resolve(3);
}, 1000);
});
}
function addAB(a,b){
return a+b
}
function getResult(){
var obj={};
Promise.resolve().then(function(){
return getA()
})
.then(function(a){
obj.a=a;
})
.then(function(){
return getB()
})
.then(function(b){
obj.b=b;
return obj;
})
.then(function(obj){
return addAB(obj['a'],obj['b'])
})
.then(data=>{
console.log(data)
})
.catch(e => console.log(e));
}
getResult();
3.Promise并行请求
getA和getB并行执行,然后输出结果。如果有一个错误,就抛出错误 每一个promise都必须返回resolve结果才正确 每一个promise都不处理错误 参考:www.jianshu.com/p/dbda3053d…
/**
* 每一个promise都必须返回resolve结果才正确
* 每一个promise都不处理错误
*/
const getA = new Promise((resolve, reject) => {
//模拟异步任务
setTimeout(function(){
resolve(2);
}, 1000)
})
.then(result => result)
const getB = new Promise((resolve, reject) => {
setTimeout(function(){
// resolve(3);
reject('Error in getB');
}, 1000)
})
.then(result => result)
Promise.all([getA, getB]).then(data=>{
console.log(data)
})
.catch(e => console.log(e));
getA和getB并行执行,然后输出结果。总是返回resolve结果 每一个promise自己处理错误
/**
* 每一个promise自己处理错误
*/
const getA = new Promise((resolve, reject) => {
//模拟异步任务
setTimeout(function(){
resolve(2);
}, 1000)
})
.then(result => result)
.catch(e=>{
})
const getB = new Promise((resolve, reject) => {
setTimeout(function(){
// resolve(3);
reject('Error in getB');
}, 1000)
})
.then(result => result)
.catch(e=>e)
Promise.all([getA, getB]).then(data=>{
console.log(data)
})
.catch(e => console.log(e));
Promise.all传入同一个方法不同参数的封装 应用场景 比如你需要同时发起多页请求,需要传入页码但是方法都是一样的此时我们就可以进行封装一下,很实用的一个技巧 参考:blog.csdn.net/qq_25842063…
/*
* @params : func:你封装的方法 params: 参数的数组
*/
let getDataBind = (func, params) => {
return params.map( item => {
return func.call(null, item) //传参
})
}
/*
@params : page_no 页码
getData 可以换成你自己需要重复操作的方法,同理
*/
let getData = (page_no) => {
let saveListData = JSON.parse(localStorage.getItem(this.props.saveListData));
let params = {
page_no:page_no,
...saveListData.loadParams
}
return new Promise(resolve => {
get(this.props.sortUrl, params, this, false).then(function (data) {
resolve(data.result;);
});
})
}
Promise.all(this.getDataBind(this.getData, arrPage))
.then( resultArr => {
resultArr = resultArr.flat();//拉平数组
console.log(resultArr) //这里就获取到所有页的数据了
});
//