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();