JavaScript是一门单线程的语言,因此,JavaScript在同一个时间只能做一件事,单线程意味着,如果在同个时间有多个任务的话,这些任务就需要进行排队,前一个任务执行完,才会执行下一个任务,会造成运行阻塞,严重影响用户体验。
2. 异步异步任务是指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,例如图片、音乐的加载,http请求等。
注意:异步任务又分为微任务、宏任务。
微任务包括:
Promise.then
Promise.catch
Promise.finally
Object.observe
MutationObserver
process.nextTick(Vue、Node.js 环境)
宏任务包括:
script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 环境)
Promise
1) 什么是Promise?
接下来请注意蓝色字体部分,能帮助您更快阅读和理解本文章~
Promise是异步编程的一种解决方案,也是异步回调的语法糖,可用于解决回调地狱的问题,并支持多个并发的请求,我们平时使用的axios就是基于Promise进行了封装。Promise其实是一个构造函数,自己身上有resolve、reject、all、race这几个方法,原型上有then、catch等方法,它将原来的回调写法分离出来,在异步 *** 作完成后采用链式调用的方式执行回调函数。
Promise对象有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。可通过resolve、reject方法改变状态,并且只有两种可能:从pending变为fulfilled、从pending变为rejected,一旦状态改变,就不会再变,任何时候都可以得到这个结果。
注意:下列解析各个场景
在Promise对象中调用resolve方法,将执行then方法的第一个回调,我们就能捕捉到执行成功的情况,并将Promise对象的状态由pending变为fulfilled。
3) reject在Promise对象中调用reject方法,将执行then方法的第二个回调,我们就能捕捉到执行失败的情况,并将Promise对象的状态由pending变为rejected。
4) thenthen方法有两个回调,第一个对应resolve的回调,第二个对应reject的回调。(也就是说then方法中接受两个回调,一个成功的回调函数,一个失败的回调函数,并且能在回调函数中拿到成功的数据和失败的原因)
function promiseClick(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
//生成1-10的随机数
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
};
promiseClick().then(
function(data){
console.log('resolved成功回调');
console.log('成功回调接受的值:',data);
},
function(reason){
console.log('rejected失败回调');
console.log('失败执行回调抛出失败原因:',reason);
}
);
执行结果:
与try catch类似,catch就是用来捕获异常的,它有两个作用:
① 它和then方法中第二个回调是一样的,如果then方法中没有写第二个回调,那么catch方法就会捕获reject出来的值;
② 在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(throw new Error( ))或代码出错了,那么并不会报错卡死js,而是会进到这个catch方法中。
function promiseClick(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
//生成1-10的随机数
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
};
promiseClick().then(
function(data){
console.log('resolved成功回调');
console.log('成功回调接受的值:',data);
console.log(noData);
}
).catch(
function(reason){
console.log('catch到rejected失败回调');
console.log('catch失败执行回调抛出失败原因:',reason);
}
);
第一种情况执行结果:
第二种情况执行结果:
与try catch finally类似,该方法用于指定不管Promise对象最后状态如何,都会执行的 *** 作。
function promiseClick(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
//生成1-10的随机数
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
};
promiseClick().then(
function(data){
console.log('resolved成功回调');
console.log('成功回调接受的值:',data);
}
).catch(
function(reason){
console.log('catch到rejected失败回调');
console.log('catch失败执行回调抛出失败原因:',reason);
}
).finally(
function(){
console.log('无论怎样都要执行的代码');
}
);
执行结果:
我们可能会遇到这样的场景:比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。这个时候Promise.all方法就发挥它独特的魅力。
Promise.all可以将多个Promise实例包装成一个新的Promise实例。该方法提供了并行执行异步 *** 作的能力,并且在所有异步 *** 作执行完后且执行结果都是成功的时候才执行then方法第一个回调(all统一执行完所有Promise并将resolve的值存在一个数组里面返回给then方法),当有一个Promise失败的时候执行then方法的第二个回调或catch方法的回调,且只能捕获第一个失败的Promise的错误,其余的Promise还会继续执行,但不进入任何回调(不管成功还是失败)。
function promiseClick1(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
//生成1-10的随机数
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
};
function promiseClick2(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
//生成1-10的随机数
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
};
function promiseClick3(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
//生成1-10的随机数
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
};
Promise.all([promiseClick3(), promiseClick2(), promiseClick1()])
.then(function(results){
// 全部Promise执行完成且都成功时进入
console.log(results);
}).catch(function(error){
// 首个异步操作执行失败时进入,后续Promise执行失败将不会再进入
console.log(error);
});
执行结果:
成功:
失败:
需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。
既然all是并行执行异步 *** 作,那么我们应该猜到race是干嘛的,顾名思义,race意为“赛跑”,谁先执行完成就先执行回调。先执行完的不管是进行了race的成功回调还是失败回调,其余的Promise会继续执行,但不会再进入race的任何回调。
function promiseClick1(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
//生成1-10的随机数
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
};
function promiseClick2(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
//生成1-10的随机数
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 3000);
})
return p
};
function promiseClick3(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
//生成1-10的随机数
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 4000);
})
return p
};
Promise.race([promiseClick3(), promiseClick2(), promiseClick1()])
.then(function(results){
// 只要有一个Promise执行成功就进入,后续的Promise执行成功将不会再进入
console.log(results);
}).catch(function(error){
// 只要有一个Promise执行失败就进入,后续的Promise执行失败将不会再进入
console.log(error);
});
执行结果:
成功:
失败:
race的使用场景:自定义限制请求超时时间,例如我想在10s内请求成功的话就走then方法,否则进入reject的回调。
//请求某个table数据
function requestTableList(){
var p = new Promise((resolve, reject) => {
//去后台请求数据,这里可以是ajax,可以是axios,可以是fetch
resolve(res);
});
return p;
}
//延时函数,用于给请求计时 10s
function timeout(){
var p = new Promise((resolve, reject) => {
setTimeout(() => {
reject('请求超时');
}, 10000);
});
return p;
}
Promise.race([requestTableList(), timeout()])
.then((data) =>{
//进行成功回调处理
console.log(data);
}).catch((err) => {
// 失败回调处理
console.log(err);
});
谢谢各位抬爱~~
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)