在搞懂Promise之前,首先得先知道为什么会出现Promise
Promise出现的缘由?
在Promise出来之前,要想在一个网络请求结果到达之后再去执行其他的请求,也就是一个请求依赖于上一个请求结果,那么就可能造成不断嵌套的情况,如下:
$.ajax({
url: 'xxx',
success: function () {
$.ajax({
url: 'yyy',
success:function () {
$.ajax({
url: 'zzz',
success: function () {
...
}
})
}
})
}
})
这样就形成了循环嵌套,一层套一层,形成了 回调地狱,这样就导致代码的臃肿,可读性差,耦合度高,可服用性差,这时就到Promise闪亮登场了
Promise含义
Promise是异步编程的一种解决方案,比传统的解决方案——回调和事件监听更合理和强大。
Promise就像一个容器,保存着未来才会执行事件的结果.Promise就是一个对象,可以获取异步操作的消息。
Promise特点:
- Promise对象状态不受外界的影响。Promise有三种状态:pending进行中、resolve已成功、reject已失败。只有异步操作的结果可以决定Promise对象处于哪种状态,其他任何操作都不能改变对象的状态
- Promise对象状态一旦改变就不能再变,这只有两种情况:pending到resolve或者pending到reject的转变,一旦状态改变了,状态相当于凝固了,给promise对象添加任何回调,得到的还是那种结果
Promise相关Api
1.Promise对象自身上的api
Promise.resove
Promise.resolve(val) 是将val转换成promise对象,最后的结果还要根据它的参数而决定:
1、val是thenable(有then方法)的对象,那么Promise.resove会追踪这个对象的then方法,也就是将val这个对象转换为Promise对象,然后执行thenable的then方法
2、val是个Promise对象,那么Promise.resolve会把这个Promise原封不动的返回
3、val不具有then方法或者根本不是对象,那么Promise.resolve会返回一个状态为resolve的Promise对象,它的resove的回调函数参数就是这个val
Promise.reject
Promise.reject返回一个状态为reject的Promise对象,跟Promise.resolve不同的是,Promise.resolve会把接收的参数原封不动的当做reject的理由,变成后续回调的参数
Promise.all([a, b, c])
Promise.all接收一个数组或者具有iterator的对象,会将多个Promise转化成一个Promise,如果传入的不是Promise对象,那么会通过调用Promise.resolve将它转化成对象。只有a,b,c三个对象的状态都变成了resolve状态,那么最后得到的promise对象才是resolve状态,a,b,c的返回值组成数组传递给回调函数;一旦a,b,c中有一个变成了reject状态,那么得到的Promise对象就是reject状态,并将那个reject的返回值传递给回调函数
2.Promise实例对象的api
Promise.prototype.then
Promise.prototype.then是Promise对象状态改变的回调函数,接收两个参数,分别是resolve状态的回调和reject状态的回调,then方法里返回一个新的Promise对象不是原来的对象,因此可以链式调用,可以在then里返回一个Promise对象(有异步操作),这时后一个回调就要等这个Promise状态改变才被调用
Promise.prototype.catch
Promise.prototype.catch是.then(null, rejection)和.then(undefined, rejection)的别名,如果前面的Promise链中有Promise状态变为reject,就会调用catch的回调,或者then回调执行过程中发生错误,也会执行catch的相关回调,也就是用于捕捉错误
Promise.prototype.finally
Promise.prototype.finally不论Promise状态为哪种,都会执行finally的操作,因此finally的回调里没有参数,因为不用依赖于Promise的状态都会执行的操作。实际中可以在finally中设置loading的为false,不论Promise的异步操作是成功还是失败,加载的字段loading都应该是完成的状态
Promise的问题
- promise一旦创建立即执行,不能中途取消
- 如果不设置回调,Promise内部的错误无法在外部捕获
- 当状态为pending时,无法得知目前进展到哪一阶段
基础使用
1.异步加载图片
function loadPic(url) {
return new Promise((resolve, reject) {
let image = new Image();
image.onload = function () {
resolve(image)
}
image.onerror = function () {
reject(new Error('Not get image at '+ url))
}
image.src = url;
})
}
2. 使用promise封装ajax操作
function ajax(url, method, data) {
return new Promise((resolve, reject) {
let xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP')
}
if (method === 'GET') {
xhr.open(method, url+"?"+data, true)
} else {
xhr.open(method, url, true)
}
})
xhr.onreadstatechange = function () {
if (this.readystate !== 4) {
return;
}
if (this.status === 200) {
resolve(this.responseText)
} else {
reject(new Error(this.statusText))
}
}
if (method === 'GET') {
xhr.send();
} else {
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(data)
}
}