都知道javaScript代码是单线程执行的,就是这个原因,导致了JavaScript中所有的网络操作,浏览器事件,都必须满足异步执行的要求,此时Promise就诞生了。简单来说Promise是一种处理异步请求的解决方案。
初始Promise
Promise三种状态
Promise 是一个构造函数,需要使用new关键字生成实例
let p = new Promise(() => {
})
console.log(p);
这里写了一个简单的Promise,输出如下结果:

可以看出在Promise未指定任何状态时,返回的状态为pending(等待状态), 还有两段代码:
let p = new Promise((resolve, reject) => {
resolve('ok')
})
console.log(p);
let p = new Promise((resolve, reject) => {
reject('err')
})
console.log(p);
两段代码的结果分别为:


不难看出,Promise的构造函数接收一个参数:函数,并且这个函数需要传入两个参数:
- resolve :异步操作执行成功后的回调函数,指定了成功的状态为fulfiled(成功状态), 且成功状态的值为你设置的ok
- reject:异步操作执行失败后的回调函数,指定了失败的状态为rejected(失败状态), 且失败状态的值为你设置的err
注:失败的回调这里控制台有报错信息,这里不是我们的代码错误,是Promise 的失败回调函数抛出了一个错误。
Promise状态不能被改变
有这么一段代码:
let p = new Promise((resolve, reject) => {
resolve('ok')
reject('err')
})
console.log(p);
此时结果:

由此得出Promise状态一旦改变就不会再变了,创造Promise实例后它会立即执行
.then
.then的链式调用
有这么一个需求:
请求三次数据,请求第一次的参数为params=321,而后两次参数分别为前一次返回的结果?
普通方式解决如下:
getData('/api/a/1?params=321',(res1) => {
console.log(res1);
getData(`/api/b/2?params=${res1.data.params}`, (res2) => {
console.log(res2);
getData(`/api/c/3?params=${res2.data.params}`, (res3) => {
console.log(res3);
})
})
})
以上这种方式就是传说中的回调地狱--> 回调里面套回调。
此时我们使用Promise来优化上述代码:
getData('/api/a/1?params=321').then((res1)=>{
console.log(res1)
return getData(`/api/b/2?params=${res1.data.params}`
}).then((res2)=>{
console.log(res2)
return getData(`/api/c/3?params=${res2.data.params}`
}).then((res3)=>{
//得到最终结果
console.log(res3)
})
被优化后的代码是通过.then解决后的结果,也是成功的解决了回调地狱的问题。
又有两段代码:
let p = new Promise((resolve, reject) => {
resolve('ok')
})
let result = p.then((res) => {
return 'ok'
})
console.log(result);
得到结果为

let p = new Promise((resolve, reject) => {
resolve('ok')
})
let result = p.then((res) => {
return new Promise((resolve, reject) => {
reject('err')
})
})
console.log(result);
结果为:

因为链式调用的结果上述代码中的p.then也是一个Promise,由此得出:
如果Promise的then方法的成功或失败返回是非Promise,那么then方法返回的Promise实例就为成功的,值为return的那个非Promise值,如果返回的是Promise,那么then方法返回的Promise实例就取决于上个Promise的返回结果。
.then的两个参数
.then可以接收两个参数,并且两个参数都是回调函数, 有这么一段代码:
let p = new Promise((resolve, reject) => {
let name = '张学友'
if (name === '刘德华') {
resolve('这是刘德华')
} else if (name === '张学友') {
resolve('这是张学友')
} else {
reject('啥也不是')
}
})
p.then((res) => {
console.log('成功',res);
}, (err) => {
console.log('失败', err);
})
上述代码当你随意切换name的值会发现,你使用resolve指定为成功的结果时,then方法就会执行第一个成功回调, 若你使用reject指定为失败的结果时,then方法就会执行第二个失败回调。
.catch
首先我来演示一个错误:
let p = new Promise((resolve, reject) => {
resolve('ok')
})
p.then((res) => {
console.log(res);
console.log(a);
},(err)=>{
console.log(err);
})
如上述代码所示,我定义了一个为定义的变量a,运行结果如下图:

可以看出报错终止了代码的运行,,错误回调并没捕获错误的结果。 此时我换成catch:
let p = new Promise((resolve, reject) => {
resolve('ok')
})
p.then((res) => {
console.log(res);
console.log(a);
}).catch((err)=>{
console.log(err);
})
结果为:

也就是说进入catch中时,把错误原因传到参数中,即便有错误代码也不会报错了,与try/catch相似。
Promise.all()
Promise下的all方法接受一个由多个Promise组成的数组,所有Promise结果成功,才返回成功 的Promise回调, 上代码:
function getLunbo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('请求轮播图成功')
}, 1000)
})
}
function getTab() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('请求tab栏成功成功')
}, 2200)
})
}
function getLayOut() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('请求侧边栏成功')
}, 3000)
})
}
function getPic() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('请求图片成功')
}, 1200)
})
}
let a = getLunbo()
let b = getTab()
let c = getLayOut()
let d = getPic()
let all = Promise.all([a, b, c, d]).then((value) => {
console.log(value);
console.log('请求所有数据成功');
})
结果如下

如果全部成功,就返回所有成功结果组成的数组,如果其中一个Promise返回失败的结果则:

Promise.any()
Promise下的any方法也接受一个由多个Promise组成的数组 , 一个Promise返回结果为成功,整体就返回成功的promise,所有的都失败才返回失败的promise。
let x1 = new Promise((resolve, reject) => {
resolve('ok')
})
let x2 = new Promise((resolve, reject) => {
reject('err')
})
let x3 = new Promise((resolve, reject) => {
reject('err1')
})
let any = Promise.any([x1, x2, x3]).then((value) => {
console.log(value);
})
console.log(any);
结果为

如果都是失败的Promise则:

Promise.race()
race 赛跑的意思,以第一个 有结果的promise为主,成功即为成功,失败即为失败
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(2);
}, 3000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
}, 5000)
})
const result = Promise.race([p3, p1, p2]);
console.log(result);
上述代码执行最快的是第一个,所以Promise.race([p3, p1, p2]);的结果取决于第一个,第一个为pending,result的结果就是pending,为成功就成功,为失败就失败。
Promise.finlly()
const p1 = new Promise((resolve, reject) => {
//resolve('ok');
reject('error');
});
p1.then(value => {
console.log(value);
}).catch(reason => {
console.log(reason);
}).finally(() => {
console.log('最终我被执行了...');
})
不难看出,不管成功与否,失败与否都会执行finally(), 且finally回调函数不接收参数
Promise.allSettled()
当所有的异步操作都有结果时,包装实例才结束,返回成功的Promise, 目前我未曾用过这个方法,后续我将补充
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];
let result = Promise.allSettled(promises).then((results) => results.forEach((result) => console.log(result.status)));
//返回成功的Promise
console.log(result);
上述代码摘自MDN
Promise.resolve()
当Promise.resolve()中传入了非Promise,那么包裹对象返回成功的Promise,成功的结果为非Promise的值,如果传入的是Promise,那么包裹对象返回的结果为Promise返回的结果
Promise.reject()
直接指定为失败状态的Promise,返回一个带有拒绝原因reason参数的Promise对象。
anync与await
await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待,等待成功的回调。
await必须写在async函数中,但是async函数中可以没有await
如果await的promise失败了,就会抛出异常,需要通过try...catch捕获处理
async function getData () {
try{
//成功
let res1 = await getDataList('/api/a/1?params=123');
}catch(err){
//失败
console.log(err.message)
}
}
上述代码anync与await的基本使用,后续还会补充。
最后
关于Promise的总结:
1.Promise可以解决代码的回调地狱(回调里面套回调),从而简化代码
2.Promise可以解决异步的问题,但本身不能说Promise是异步的
3.anync与await是开发主流,可通过try...catch捕获异常
这是我的个人博客:XieJinYang的博客 (gitee.io)
希望大家有所收获!!!!!!!!!!!!!!!!!!!!!!!!