ES6中有一个非常重要和好用的特性就是Promise
那么Promise到底是做什么的呢?
基本概念
简单来说,Promise就是异步编程的一种解决方案,其实就是一个构造函数。自己身上有resolve、reject、all这几个方法。原型链上有then、catch等方法。
两大特点
- 对象的状态不受外界影响。Promise对象代表着一个异步操作,它有三种状态:pending(进行中)、fulfilled(已完成)、rejected(已失败)。
只有异步操作的结果,可以决定当前是哪一种状态,任何操作都无法改变这个状态。
2.一旦状态改变,就不会再变,任何时候都可以得到这个状态。
Promise对象的状态改变,只有两种结果:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会在改变了,会一直保持这个结果。
基本使用
先new 一个最基本的Promise对象
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('执行完成Promise');
resolve('要返回的任何数据:接口数据等等');
},2000)
})
刷新页面会打印如下结果
它的执行过程是:执行了一个异步操作(setTimeout),2秒之后,输出图中结果,并且调用了resolve方法。
注意:这里我只是new了一个对象,并没有调用它,里面传进去的函数就已经执行了。所以一般情况下我们用Promise的时候都是包在一个函数中,在需要的时候去运行这个函数。
<div onclick='promiseClick()'>开始异步请求</div>
const promiseClick = () => {
console.log('点击方法被执行')
let p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行完成Promise');
resolve('要返回的任何数据:接口数据等等');
}, 2000)
})
return p
}
此时刷新页面,控制台没有打印任何信息,当我们点击div之后,打印台先后打出
这样我们只有在调用函数的时候才会被执行,那resolve是什么?
如上图我们在包装好的函最后,return 出一个Promise对象§,也就是说,执行这个函数我们得到了一个Promise对象。
resolve/then
接下来就可以使用Promise对象身上的then方法了。
promiseClick().then(item=>{
console.log(item);
})

第一行代码直接出现,2秒之后打印Promise对象里面的,当我们多次点击之后,resolve执行的代码依旧只打印一次。验证了Promise对象的状态一旦发生,就不会在改变。
这个时候你会发现一件事情,then这不是和平时的回调函数一样嘛,在promiseClick这个异步函数执行完成之后被执行。那么Promise的精髓就来了,需要多层回调的时候,Promise就能简化层层回调的写法。
function run1() {
let p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('异步任务1完成');
resolve('随便的数据1')
}, 2000)
})
return p
}
function run2() {
let p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('异步任务2完成');
resolve('随便的数据2')
}, 2000)
})
return p
}
promiseClick()
.then(item => {
console.log(item);
return run1();
})
.then(item => {
console.log(item);
return run2()
})
.then(item=>{
console.log(item);
})
在控制台打印的结果如下
间隔2秒打印一个红框里面的内容,这样就能够按照顺序间隔2秒输出一个异步回调中的内容。
reject/catch
以上是对promise的resolve用法进行了解释,相当于resolve是对promise成功时候的回调,它把promise的状态修改为fullfiled,那么,reject就是失败的时候的回调,他把promise的状态修改为rejected,这样我们在catch中就能捕捉到,然后执行“失败”情况的回调。
new Promise((resolve, reject) => {
setTimeout((data) => {
//成功的时候调用resolve
resolve('hello World');
//失败的时候执行reject
reject('error message');
})
}).then((data)=>{
console.log(data)
}).catch((err)=>{
console.log(err)
})
all
与then同级的一个方法,该方法提供了并行执行异步操作的能力,
在所有异步执行并执行结果都是成功的时候进行回调。
function run1() {
let p = new Promise((resolve, reject) => {
setTimeout(() => {
let nums = Math.ceil(Math.random() * 10)
console.log('随机生成的数字:' + nums);
if (nums <= 5) {
resolve(nums)
} else {
reject('数字太大了')
}
}, 2000)
})
return p;
}
function run2() {
let p = new Promise((resolve, reject) => {
setTimeout(() => {
let nums = Math.ceil(Math.random() * 10)
console.log('随机生成的数字:' + nums);
if (nums <= 5) {
resolve(nums)
} else {
reject('数字太大了')
}
}, 2000)
})
return p;
}
function run3() {
let p = new Promise((resolve, reject) => {
setTimeout(() => {
let nums = Math.ceil(Math.random() * 20)
console.log('随机生成的数字:' + nums);
if (nums <= 10) {
resolve(nums)
} else {
reject('数字太大了')
}
}, 2000)
})
return p;
}
Promise
.all([run1(),run2(),run3()])
.then(result=>{
console.log(result);
})

race
all 是等所有异步操作执行完毕且成功之后在执行then方法,race正好是相反的,
谁先执行完毕谁就先执行回调。先执行完的不管是进行了race的成功回调还是失败回调,其余的将不会再进入race的任何回调。
function run1() {
let p = new Promise((resolve, reject) => {
setTimeout(function () {
let num = Math.ceil(Math.random() * 20); //生成1-10的随机数
console.log('2s随机数生成的值:', num)
if (num <= 10) {
resolve(num);
} else {
reject('2s数字大于10了即将执行失败回调');
}
}, 2000);
})
return p
}
function run2() {
let p = new Promise((resolve, reject) => {
setTimeout(function () {
let num = Math.ceil(Math.random() * 20); //生成1-10的随机数
console.log('3s随机数生成的值:', num)
if (num <= 10) {
resolve(num);
} else {
reject('3s数字大于10了即将执行失败回调');
}
}, 3000);
})
return p
}
function run3() {
let p = new Promise((resolve, reject) => {
setTimeout(function () {
let num = Math.ceil(Math.random() * 20); //生成1-10的随机数
console.log('4s随机数生成的值:', num)
if (num <= 10) {
resolve(num);
} else {
reject('4s数字太于10了即将执行失败回调');
}
}, 4000);
})
return p
}
Promise
.race([run1(), run2(), run3()])
.then(function (results) {
console.log('成功', results);
}, function (reason) {
console.log('失败', reason);
});

例子
在一个请求在10s内请求成功的话就走then方法,如果10s内没有请求成功的话进入reject回调执行另一个操作。
function requestData(){
let p = new Promise((resolve,reject)=>{
//请求的数据
resolve(res);
})
return p;
}
function TimeOut(){
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('请求超时');
},10000)
})
return p;
}
Promise.race([requestData(),TimeOut])
.then(res=>{
console.log(res);
})
.catch(err=>{
console.log(err);
})