Promise
基本概念
- promise:是ES6中新增的异步编程解决方案,体现在代码中它是一个对象,可以通过 Promise构造函数来实例化。
new Promise(cb) ===>实例的基本使用 Pending Resolved Rejected
两个原型方法
- Promise.prototype.then()
- Promise.prototype.catch()
两个常用的静态方法
- Promise.all()
- Promise.resolve()
首先我们来解释一下什么是异步?
打个比方,你想买一套房子,这个时候你需要去售楼处咨询一下,所以你就给售楼处打了一个电话,于是就有一个大叔接了你的电话,然后就问你:
“小伙子,你想买什么样的房子啊?”
,然后你就说
“要什么什么样的”,
这个时候大叔就需要去看看有没有符合你说的要求的房子,大叔就会和你说:
“小伙子你等一下,我帮你查一下”
,这个时候你在电话里等啊等,不一会大叔回来告诉你,
“查了,你说的这个房子的类型没有了”,
然后挂了电话。
这个过程中,打电话的时候,一直在等待对方的结果,这个时候其实就是一个同步的过程,那么相反的就是异步,异步就好比你打了一个电弧,不是一个大叔接的,而是一个售楼小妹接的,这个小妹就和你说,先生你稍等一下,你可以先挂了电话,我去查一下,如果查好了我在打你的电话给你回复你,然后告诉你结果。
这是打电话之后你可以挂了,挂了之后该干嘛干嘛去,然后等她的结果就可以了,这个时候可能小妹查好了,给你回了个电话告诉你结果,就OK了。这个过程就是异步的。
那么Promise对象,就是处理异步过程的一个对象
既然学习Promise呢,我们主要通过三个方面去学习它。
首先是它的构造函数new Promise(cb),然后是构造函数原型上的方法,已经构造函数本身的两个静态方法。
那么我们先来看看Promise对象
// new Promise(cb)
// Pending(进行中) ===> Resolved(已完成)
// Pending(进行中) ===> Rejected(已失败)
一个Promise对象它的状态完全取决于它的异步操作的结果来决定的,如果说这个异步操作成功了,那正在进行当中的时候就是Pending,如果已经成功了就会变成Resolved(已完成),如果失败了就会变成Rejected(已失败)。
同时这个Promise对象它的状态一旦改变之后,就不能再变了。也就是说成功了就是成功,失败了也不可能再变成功。
那这是怎么回事呢,我们演示一下,我们准备一个数组,里面有一堆地址
接下来,我们实例化一个对象,这个对象当中,可以接收一个参数
resolve代表异步操作执行成功的回调函数,reject代表异步操作失败时候的回调函数。
这里我们以图片加载为例子来说:
const p = new Promise(function(resolve,reject){
const img = new Image();
img.src = imgs[0];
img.onload = function(){
resolve(this); //当图片加载成功的时候就执行resolve
};
img.onerror = function(err){
reject(err);//当图片加载失败的时候我们就返回失败的信息
}
});
这个时候我们就创建完成的了Promise对象,这个时候运行一下什么都没有,控制台也没有什么信息,那么怎么知道它完成了呢?这个时候就需要Promise对象原型上的两个方法了。
两个原型方法
- Promise.prototype.then()
- Promise.prototype.catch()
这里面一旦完成就可以调用then了,如下
//这里面可以接收两个参数,第一个参数是一个函数,就是resolve;第二个参数也是一个函数,就是reject
//同时函数里面参数,我们就可以指定了,这么这里面通过onload执行成功传了一个参数
//我们做一个简单的操作,把图片添加到body当中
console.log(123);
p.then(function(img){
console.log("加载完成");
document.body.appendChild(img);//这个时候保存一下,可以发现一张图片就被加载到页面中了,而且过程全部是异步的
})
console.log(456);
我们发现首先显示的是123,然后显示456,最后显示“加载完成”,这个就说明了 Promise实际上是一个异步的操作。它并不会影响后面的代码执行。
.then()是promise原型上的一个方法,它是promise异步操作,执行之后要调用的一个函数,它能调用两个回调函数,一个是执行成功的回调函数,另一个是执行失败的回调函数。
这时我们再把src设为空;它就打印出了报错信息。
一般情况下.then()当中不推荐写第二个参数捕获异常,而是使用原型当中的第二个方法.catch()来捕获异常。
这个时候依然显示报错信息.
以上就是Promise原型上的两个方法,一个叫.then()一个.catch()。分别是用来调用Promise异步结束之后结果的两个回调函数。
我们将这个函数封装一下
function loadImg(url){
const p = new Promise(function(resolve,reject){
const img = new Image();
img.onload = function(){
resolve(this);
};
img.onerror = function(){
reject(new Error("图片加载失败 "));
};
});
return p;
}
//调用
loadImg(img[0]).then(function(){
document.body.appendChild(img)
})
接下来,我们来看看Promise.all
Promise.all 可以将多个Promise实例包装成一个新的Promise实例
当所有的Promise实例的状态都变成resolved,Promise.all的状态才会变成resolved,此时返回值组成一个数组,传递给then中的resolve函数。
只要其中一个被rejected,Promise.all的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
const allDone = Promise.all(loading(imgs[0]),loading(imgs[1]),loading(imgs[2]));
allDone.then(function(datas){
console.log(datas);//[img,img,img]
//我们可以使用forEach方法将图片加到页面当中
datas.forEach(function(item,i){
document.body.appendChild(item);
});
})
可以发现三张图片同时被加载到页面当中
那么如果有个失败呢?
接下来,我们在来介绍一下Promise.resolve()
它主要是将其他对象转换成Promise对象
参数是Promise实例,将不做任何修改,原封不动地返回这个实例。
Promise.resolve(loadImg(imgs[0])).then(function(img){
document.body.appendChild(img);
})
将对象是Promise实例,将不做任何修改,原封不动地返回这个实例。
Promise.resolve({
then(resolve,reject){
const img = new Image();
img.src = imgs[1];
img.onload = function(){
resolve(this);
}
}
}).then(function (img){
document.body.appendChild(img);
})
参数是一个基本数据类型或者不传参数,那么返回一个状态为 resolved的Promise对象
Promise.resolve('zhang').then(function(str){
console.log(str);
})
const p = Promise.resolve();
console.log();