Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法。Promise对象属性如下图所示:
创建一个Promise实例的语法
var promise=new Promise(function(resolve,reject){
resolve()//或者reject()
});
ECMAscript 6 原生提供了 Promise 对象。
Promise是JS 中进行异步编程的新解决方法
Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。
特点:
缺点:
Promise有三种状态:pending(等待)、fulfilled(已满足)和rejected(已拒绝)
Promise的状态只有两种走向:pending(等待)—>fulfilled(已满足)和pending(等待)—>rejected(已拒绝)
当状态为fulfilled(已满足)和或rejected(已拒绝),不会再变更状态
//当Promise对象创建到执行resolve()和reject()方法前,Promise对象一直处于pending(等待)状态
//如果执行的是resolve()方法,则pending(等待)—>fulfilled(已满足)
//如果执行的是reject()方法,则pending(等待)—>rejected(已拒绝)
var promise=new Promise(function(resolve,reject){
resolve()//或者reject()
});
.all()的作用是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调。
var p = new Promise(function (resolve, reject) {
resolve("成功执行resolve方法")
})
console.log(p);
console.dir(Promise);
function promise1() {
let p = new Promise(function (resolve, reject) {
setTimeout(function () {
var num = Math.ceil(Math.random() * 10); //生成1-10的随机数
console.log('随机数生成的值:', num)
if (num <= 10) {
resolve(num);
}
else {
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
function promise2() {
let p = new Promise(function (resolve, reject) {
setTimeout(function () {
var num = Math.ceil(Math.random() * 10); //生成1-10的随机数
console.log('随机数生成的值:', num)
if (num <= 10) {
resolve(num);
}
else {
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
function promise3() {
let p = new Promise(function (resolve, reject) {
setTimeout(function () {
var num = Math.ceil(Math.random() * 10); //生成1-10的随机数
console.log('随机数生成的值:', num)
if (num <= 10) {
resolve(num);
}
else {
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
Promise
.all([promise3(), promise2(), promise1()])
.then(function (results) {
console.log(results);
});
最后输出结果为:最后一行输出的数组则是.all()方法输出的,只有当全部promise对象都成功变为fulfilled(已满足)状态,.all()方法才会成功返回
.allSettled()的作用与.all()方法类似,都是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调。
将上述例子所用的all方法改为allSettled方法,输出如下图:
从中我们不难看出**.all()方法与.allSettled()方法的区别**
.race()的作用是接收一组异步任务,然后并行执行异步任务,只保留取第一个执行完成的异步操作的结果,其他的方法仍在执行,不过执行结果会被抛弃。
将上述例子所用的all方法改为race方法,输出如下图:当第一个promise对象成功变为fulfilled(已满足)状态,.race()方法就会成功返回该对象的值,之后的对象如果也成功满足的话,会执行但结果会被抛弃。
.then():then会返回一个状态为pending(等待)的Promise
then方法接受的参数是函数,一个是成功的回调函数,一个是失败的函数,两个函数的参数为Promise对象的返回值或者resolve和reject方法中的参数。代码示例:
var p = new Promise(function (resolve, reject) {
var num=10
if(num<20){
resolve(num)
}else{
reject("你选的数太大了")
}
})
p.then((value)=>{
console.log("成功进入到then方法的成功回调",value);
},(reason)=>{
console.log("成功进入到then方法的失败回调",reason);
})
console.log(p);//成功进入到then方法的成功回调 10
.then()方法中的第一个参数为成功的回调函数,value参数为resolve()方法中的值;而第二个参数为失败的回调函数,reason参数为reject()方法中的值。
.then()方法是可以多次调用的,多次调用可以解决回调地狱的问题。何谓回调地狱?
简单来讲,回调函数嵌套回调函数即为回调地狱,示例代码:
setTimeout(function () { //第一层
console.log('回调第一层');
setTimeout(function () { //第二程
console.log('回调第二层');
setTimeout(function () { //第三层
console.log('回调第三层');
}, 1000)
}, 2000)
}, 3000)
总的来说:回调地狱就是为是实现代码顺序执行而出现的一种操作,它会造成我们的代码可读性非常差,后期不好维护。而通过Promise可以解决该问题,示例代码如下:
function fn(str){
var p=new Promise(function(resolve,reject){
//处理异步任务
var flag=true;
setTimeout(function(){
if(flag){
resolve(str)
}
else{
reject('操作失败')
}
})
})
return p;
}
fn('回调第一层')
.then((data)=>{
console.log(data);
return fn('回调第二层');
})
.then((data)=>{
console.log(data);
return fn('回调第三层')
})
.then((data)=>{
console.log(data);
})
.catch((data)=>{
console.log(data);
})
输出结果与上述结果一样,使用Promise可以解决回调地狱问题,增强代码可读性。
.catch()
Promise对象中的reject是用来抛出异常的,而.catch()就是用来捕获异常的,也就是和then方法中接受的第二参数rejected的回调是一样的。如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。示例代码:
var p = new Promise(function (resolve, reject) {
var num=30
if(num<20){
resolve(num)
}else{
reject("你选的数太大了")
}
})
p.then((value)=>{
console.log("成功进入到then方法的成功回调",value);
}).catch(function(reason){
console.log("catch方法",reason);
})
console.log(p);//输出catch方法 你选的数太大了
.catch()方法与.then()中第二个参数的区别
.finally()
.finally()方法不管Promise对象最后的状态如何都会执行
.finally()方法的回调函数不接受任何的参数,也就是说你在.finally()函数中是无法知道Promise最终的状态是resolved还是rejected的
它最终返回的默认会是一个上一次的Promise对象值,不过如果抛出的是一个异常则返回异常的Promise对象。
finally本质上是then方法的特例
注意:
Uncaught (in promise) TypeError: Chaining cycle detected for promise #\<Promise>
Promise.all
1.多个请求结果合并在一起
2.合并请求结果并处理错误
3.验证多个请求结果是否都是满足条件
Promise.race
1.图片请求超时
2.请求超时提示
Promise.prototype.then
1.下个请求依赖上个请求的结果
2.中间件功能使用
1.请试写出以下代码的输出顺序。
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
console.log("script start");
setTimeout(function() {
console.log("setTimeout");
}, 0);
async1();
new Promise(function(resolve) {
console.log("promise1");
resolve();
}).then(function() {
console.log("promise2");
});
console.log('script end')
输出结果为:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
在理解该题目前,我需要引入以下概念:
宏队列和微队列
宏队列:用来保存待执行的宏任务,,比如setTimeout、setInterval、script标签、DOM回调、ajax回调等。
微队列:用来保存待执行的微任务,比如:promise、async-await、Object.observe等。
执行顺序:
1.执行一个宏任务(栈中没有就从事件队列中获取)
2.执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
3.宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
4.当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
5.渲染完毕后,JS线程会继续接管,开始下一个宏任务(从事件队列中获取)
该题的执行顺序是: