Promise
是异步编程的解决方案。举个例子,有一个函数A,A执行一些步骤,A执行完要执行函数B,这里有个顺序问题,就是A执行完执行B。那在程序上如何实现这个场景呢?
这里有两种方式,一种是通过回调的方式实现,另外一种是通过事件触发的方式实现。而Promise
是区别与以上两种方式的。
一、Promise的基本用法
先来回顾下ES5
中利用回调来解决异步的问题
我们模拟一个前端与服务端通信时的ajax
过程,添加一个callback
回调方法,用于接收服务端的返回结果。这里用定时器setTimeout
模拟了一个通信的过程,一秒钟之后会调用回调方法。
{
let ajax = function (callback) {
console.log('执行');
setTimeout(() => {
callback && callback.call();
}, 1000);
};
ajax(function () {
console.log('timeout1');
})
}
先输出了执行
,一秒钟之后执行了回调函数,输出了timeout1
,这样就实现了一个异步操作。
但是开发过程中经常会遇到比较复杂的情况,先执行A再执行B,甚至执行完B再执行C,如果用ES5中回调
的方式去处理,这么这个代码将非常复杂。除此之外,这个代码的复杂还会影响后期的代码维护,无法一眼看出代码执行的顺序问题,很难阅读,所以呢,为了解决这些问题,就引出了Promise
这个解决方案。
函数执行完之后会返回一个对象
,这个对象就是Promise
的实例,这个实例有一个then
方法去执行下一步的功能。这里会有两个参数resolve
和 reject
,resolve
表示要执行下一步操作,而reject
表示中断当前的操作
{
let ajax = function () {
console.log('执行2');
/**
* resolve:要执行下一步的操作
* reject:要中断当前的操作
*/
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve();
}, 1000);
})
};
ajax().then(() => {
console.log('promise', 'timeout2');
});
}
执行结果:
先打印执行2
,一秒钟之后再打印出timeout2
那么对于执行完函数A再执行函数B的场景,利用Promise
就很容易实现了
{
let ajax = function () {
console.log('执行3');
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve();
}, 1000);
})
};
ajax()
.then(() => {
return new Promise(function (resolve, reject) {
console.log('执行3-1');
setTimeout(function () {
resolve();
}, 2000);
})
})
.then(() => {
console.log('timeout3');
});
}
上面的代码就模拟了两个函数的执行过程。输出执行3
,一秒后打印出执行3-1
,再过两秒后输出timeout3
可以清楚看到利用Promise实现的优势,多个函数执行只要再前一个Promise
的then
方法中再new
一个Promise
,同时再添加then
用于接收下一个函数的执行结果。整个结构非常清晰,代码可维护。
但是这边还要考虑一个问题,如果在这个串行过程中(A==>B==>C),其中某个函数执行出现了异常,那如何来捕获这个错误?幸运的是Promise
已经提供了这样一个方法catch
,可以用来捕获异常错误。
{
let ajax = function (num) {
console.log('执行4', num);
/**
* resolve:要执行下一步的操作
* reject:要终止当前的操作
*/
return new Promise((resolve, reject) => {
if (num > 5) {
resolve();
} else {
throw new Error('出错啦');
}
})
};
ajax(6).then(() => {
console.log('log', 6);
}).catch(err => {
console.log('catch', err);
});
//修改传入的num值,num小于5就会抛出错误,catch能捕捉到该错误
// ajax(2).then(() => {
// console.log('log', 6);
// }).catch(err => {
// console.log('catch', err);
// })
}
image.png
二、Promise的高级用法
-
Promise.all
在实际开发过程中,可能会遇到这样一个需求:加载三张图片,要求三张图片都加载完成后才显示在页面上。这里可以思考下应该如何实现呢?而Promise
就提供来这样一个方法(Promise.all
)
{
// 所有图片加载完(忽略加载成功或加载失败)再添加到页面
function loadImg(src) {
return new Promise(((resolve, reject) => {
let img = document.createElement('img');
img.src = src;
img.onload = function () {
resolve(img);
};
img.onerror = function (err) {
reject(err);
}
}))
}
function showImgs(imgs) {
imgs.forEach(img => {
document.body.appendChild(img);
})
}
//Promise.all 将多个Promise实例当作一个Promise实例,当所有Promise实例的状态发生改变时,这个Promise实例才会跟着发生变化
//在这里也就是说,只有当三个图片的所有的状态都完成之后,才会触发Promise.all这个新的Promise
Promise.all([
loadImg('https://pics6.baidu.com/feed/e4dde71190ef76c6f8a619195cd869fcae5167e5.jpeg?token=83461bdb4a26ce68441d12a04ce4c127&s=843053975A4226CC5F84691E0300C063'),
loadImg('https://pics2.baidu.com/feed/77094b36acaf2edd362ad591288595ef3801930f.jpeg?token=939c0e1cf863beba12e9e0dfa3f42b23'),
loadImg('https://pics7.baidu.com/feed/64380cd7912397dd701ca9865b2226b1d1a28775.jpeg?token=9df8d6fb97b587e7131aee048d334c6a')
]).then(showImgs)
}
-
Promise.race
Promise
还有个Promise.race
方法,这个方法的作用是多个Promise
实例中任何一个Promise
的状态完成后,这个新的Promise
就会被执行。利用这个方法可以显示这样一个需求:假设有三张图片,要求其中任意一张图片加载完成,就显示在页面中。
{
// 任意一张图片加载完就添加到页面
function loadImg(src) {
return new Promise(((resolve, reject) => {
let img = document.createElement('img');
img.src = src;
img.onload = function () {
resolve(img);
};
img.onerror = function (err) {
reject(err);
}
}))
}
function showImgs(img) {
let p = document.createElement('p');
p.appendChild(img);
document.body.appendChild(p);
}
//Promise.race 三个Promise中任何一个Promise的状态发生改变,这个Promise就会发生改变
//在这里也就是说,三张图片任一张图片加载完就显示在页面上,先到先得
Promise.race([
loadImg('https://pics6.baidu.com/feed/e4dde71190ef76c6f8a619195cd869fcae5167e5.jpeg?token=83461bdb4a26ce68441d12a04ce4c127&s=843053975A4226CC5F84691E0300C063'),
loadImg('https://pics2.baidu.com/feed/77094b36acaf2edd362ad591288595ef3801930f.jpeg?token=939c0e1cf863beba12e9e0dfa3f42b23'),
loadImg('https://pics7.baidu.com/feed/64380cd7912397dd701ca9865b2226b1d1a28775.jpeg?token=9df8d6fb97b587e7131aee048d334c6a')
]).then(showImgs)
}
网友评论