异步编程–Promise的用法
阅读Promise的简单实现https://blog.csdn.net/jl244981288/article/details/47166183
console.dir(Promise)--浏览器控制台查看Promise对象
目录
Promise简介
Promise的出现实际上是为了解决回调地狱的问题,在正式理解Proise的用法之前我们先来了解下什么是回调方法,看下面一段代码:
function foo(arg1, callback) {
if(arg1>5 && typeof callback === 'function') {
callback();
}
}
foo(10, function() {
console.log('我来自回调函数')
});
上面的foo函数传入的第二个参数是一个函数,当满足某种条件的时候,程序再来执行传入的这个函数,这就是一个典型的回调函数的用法。
理解了上面回调函数的用法后我们再来看一个Promise的用法:
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('我来自回调函数');
}, 3000);
});
p.then((value) => {
console.log(value)
});
代码中用new关键字实例化了一个Promise对象,在Promise的构造函数中传入了一个函数,这个函数分别传入resolve和reject两个参数,分别表示异步操作执行“成功”和执行“失败“”的情况下的回调函数,这里的“成功”和“失败”描述的不够准确,实际上应该对应着promise的fulfill和reject两个状态。
接着我们在Promise返回的对象上调用了then方法,then方法接收了两个参数,运行这段代码,3秒后会在控制台输出“我来自回调函数”。看到这里大家可能已经明白了,promise其实就是跟回调是一个意思。
Promise的应用一:处理多个相互依赖的异步请求
我们在开发的过程中肯定遇到过这样的问题,调用一个ajax请求A拿到一些数据,再根据请求A中的某些数据去请求另一个ajax接口B去查询数据,如果我们使用Promise写法应该如何解决这个问题呢?请看下面的代码:
function a(){
return new Promise(function(resolve, reject) {
$.ajax({
url:"/url1",
type: "GET",
async:true,
dataType:"json",
success:function(data){
resolve(data);
}
})
});
}
function b(id){
return new Promise(function(resolve, reject) {
$.ajax({
url:"/url2",
type: "POST",
async:true,
data:id,
dataType:"json",
success:function(data){
resolve(data);
}
})
});
}
$("#btn").click(function() {
a().then(function (data) {
b(data.id);
}).then(function(response) {
console.log(response);
});
})
上面的代码我们可以看到,通过Promise的链式调用,避免了嵌套调用时代码过于冗长的问题。
Promise的应用二:并行执行多个异步请求
Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调,注意,当所有异步执行的Promise任务都变为resolve时,该方法才会返回。看一个例子:
var p1 = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('异步任务1');
}, 3000);
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('异步任务2');
}, 2000);
});
var p3 = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('异步任务3');
}, 1000);
});
Promise.all([p1,p2,p3]).then((value) => {
console.log(value); // 打印['异步任务1','异步任务2','异步任务3']
});
上面的代码在控制台中打印的结果是[‘异步任务1’,’异步任务2’,’异步任务3’]。我们可以看到,p1对象中的setTimeout是3秒,p2对象中的setTimeout是2秒,p3对象中的setTimeout是1秒,但是在Promise.all方法中输出的结果依然会按照Promise对象传入数组中的顺序返回结果。
Promise的应用三:Promise.race的应用
Promse.race的方法和Promise.all方法有些类似。Promise.all方法是谁跑的慢,以谁为准执行回调,Promise.race相反,是谁跑的快,以谁为准执行回调。基与上面的代码进行示例:
Promise.race([p1,p2,p3]).then((value) => {
console.log(value);
});
代码执行的结果是,输出’异步任务3’,’异步任务2’,’异步任务1’。可能跟你想的不完全一致对吧?在then里面的回调开始执行时,在p3输出结果后 p2和p1并没有停止输出,而是将所有结果都输出完为止。
Promise的race方法有什么用呢?使用场景还是很多的,比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作,代码如下:
//异步请求某个资源
function getSomething()
let p = new Promise(function(resolve, reject) {
let img = new Image();
img.onload = function() {
resolve(img);
}
img.src = 'test';
});
return p;
}
//延时函数,用于给请求计时
function timeOut() {
let p = new Promise(function(resolve, reject) {
setTimeout(() => {
reject('资源请求超时');
}, 10000);
});
return p;
}
Promise
.race([getSomething(), timeOut()])
.then((resource) => {
console.log(resource);
})
.catch((error) => {
console.log(error);
});
getSomething函数会进行一个异步请求,timeOut函数是一个延时10秒的异步操作。我们把这两个返回Promise对象的函数放进race,看他们两先执行完成,如果10秒之内资源请求成功了,则执行resolve方法,资源成功请求。如果10秒之内资源没有成功请求到,那么timeOut就要先执行,则进入catch,抛出“资源请求超时”的异常。