一、Promise 是什么?
Promise: 是浏览器新增的内置类,用来管理异步;Promise本身是同步的,是用来管理异步的;传递给Promise的构造函数的回调函数是同步执行的;
let p = new Promise(function (resolve, reject) {
// 这个函数中处理异步
});
二、Promise实例对象有三种状态
- pending: 已经初始化,正在处理异步
- fulfilled: 异步处理成功
- rejected: 异步处理失败
值得注意的是,Promise的状态一旦发生变更,就会凝固,不会再发生变化;
三、Promise 用法示例
let p2 = new Promise(function (resolve, reject) {
// 这个函数是同步执行的
setTimeout(function () {
resolve('abc') // resolve的实参会传递给then方法的第一个回调函数;
})
});
- 在创建Promise示例时传递的回调函数中,存放的是异步执行的任务;
- resolve 当异步处理成功后执行的,执行的是一个事件池,收集了后面所有的then方法的第一个参数;
- reject 当异步处理失败后执行的,执行的也是一个事件池,收集了后面所有的then方法的第二个参数;
p2.then(function (data) {
console.log(1);
console.log(data);
// throw 'new err';
// return 'xyz'
return new Promise(function (resolve, reject) {
resolve('就是想解决')
})
}, function (err) {
console.log(2);
console.log(err)
}).then(function (data2) {
console.log(3);
console.log(data2)
// then方法
}, function (err2) {
console.log(4);
console.log(err2)
});
- promise实例对象的第一个then方法的回调函数会根据new Promise()时异步处理的情况来决定
- 如果是resolve状态,就会执行第一个then方法的第一个回调函数,resolve时传递的实参会传递给第一函数;
- 如果是reject就会执行第二个,reject时传递的实参会传给第二个函数
- 但是后面的then方法里面的回调函数执行哪一个取决于执行前面的then方法中函数执行的情况;
- 如果前一个then中回调没有返回promise实例,无论是第一个还是第二个执行成功了,都会执行后面的then的第一个回调函数。但是前一个then方法中报错了,就会执行第二个;
- 如果前一个then方法中返回的是一个promise实例,后面的then方法中执行哪个取决于上一个then中返回的promise实例的状态,如果是resolve了,就会执行后面的第一个函数,如果是reject了,就会执行第二个函数;
四、从现实场景看 Promise
- 首先请求
aside.json,然后从aside.json中取得最后一条数据的id,然后再请求banner.json。最后把banner.json输出
4.1 使用 jquery
$.ajax({
url: 'aside.json',
type: 'get',
cache: false,
error (err) {},
success (res) {
let [ , ,third] = res;
$.ajax({
url: 'banner.json',
type: 'get',
cache: false,
error (err) {},
success (data) {
console.log(data);
}
})
}
});
我们发现,上面代码中一层嵌套一层,如果接口多了,那么这种代码组织起来将会十分不便;也是常说的回调地狱
4.2 使用Promise
let p = new Promise(function (resolve, reject) {
$.ajax({
url: 'aside.json',
type: 'GET',
cache: false,
error(err) {
reject(err)
},
success (data) {
resolve(data)
}
})
});
p.then(([,, third]) => {
return new Promise(function (resolve, reject) {
$.ajax({
url: 'banner.json',
type: 'get',
cache: false,
error(err) {
reject(err)
},
success (data) {
resolve(data)
}
})
})
}).then((banner) => {
console.log(banner)
}).catch((err) => {
console.log(err)
});
- 一般情况下,then只放一个成功的回调函数,会把失败的回调函数中放在catch函数中;
4.3 Promise.all() 方法
- 现在有两个接口,要求必须等着两个接口全部请求完成后才能渲染数据;
类似于上面这种场景就会用到Promise的all方法;
Promise.all([promise实例1, promise实例2])
- Promise.all 是Promise的静态方法,接受一个有多个promise实例组成的数组,并且返回一个新的Promise实例;
- 如果数组中所有的Promise实例的状态都变成resolve,那么返回的新的Promise实例的状态才能变成resolve;
- 如果有一个失败,那么新返回的Promise实例的状态就会变为失败;
- 同时,会把数组中的promise实例成功的数据组成一个新的数组,传递给后面then方法的第一个函数;
示例:
function queryFn(url) {
return new Promise((resolve, reject) => {
$.ajax({
url: url,
cache: false,
error(err) {
reject(err)
},
success (data) {
resolve(data)
}
})
})
}
Promise.all([queryFn('aside.json'), queryFn('banner.json')]).then((dataArr) => {
console.log(dataArr)
}).catch((err) => {
console.log(err)
});
4.4 Promise.race() 方法
前面的一个方法的背景是若干异步都完成后再进行某个操作,还有一种常见场景是当若干异步操作,有一个完成即可进行后续操作了,这种场景下就需要使用 Promise.race() 方法:
Promise.race() 接收一个数组,数组为 Promise 对象,当其中的一个状态发生改变后,就会执行后面的 then 方法;
示例:
let p1 = new Promise((resolve, reject) => setTimeout(resolve, 1000));
let p2 = new Promise((resolve, reject) => setTimeout(resolve, 2000));
let p3 = new Promise((resolve, reject) => setTimeout(resolve, 3000));
Promise.race([p1, p2, p3]).then(res => console.log('Race'))