ES6中 Promise()对象,Promise.all()方法,Promise.race() 方法,async 函数

回调地狱

回调地狱: 因为js是单线程的, 有些时候为了代码功能需求,需要函数嵌套函数,当函数嵌套多层时,就会形成回调地狱

如何解决回调地狱: 通过Promise() 解决

模拟异步操作

  <script>
  //  模拟异步操作  (下面例子当调用函数fun2()执行顺序  2 1  3)
        function fun1(){
            setTimeout(function(){
                console.log('setTimeout1');      
                fun3()          
            }, 1000)
        }
        function fun2(){
            setTimeout(function(){
                console.log('setTimeout2');    
                fun1()            
            }, 2000)
        }
        function fun3(){
            setTimeout(function(){
                console.log('setTimeout3');               
            }, 2000)
        }
        fun2();//输出顺序   2   1  3
   </script>

回调地狱实例

 function fun() {

            setTimeout(function () {

                console.log(2);

                setTimeout(function () {

                    console.log(1);

                    setTimeout(function () {

                        console.log(3);

                    })
                })                
            })
        }
       fun();  执行顺序是  2  1   3

Promise() 对象

Promise是什么
:Promise是异步编程的一种解决方案,从语法上讲是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。

Promise() 对象:
存在三种状态:

  • 进行时 pending

  • 成功 resolve

  • 失败 reject

    状态的改变 只能从 pending 转换为 resolve; 或者 从pending 转换为 reject; 如果处于pending状态,永远不知道下一步转换为什么状态

    Promise() 接受一个函数作为参数; 函数存在两个参数(这两个参数是js原生提供的) 一个是resolve, 一个是reject

Promise()的执行机制
如果Promise()执行成功,则会调用执行 resolve(); resolve()中的参数就是执行成功的结果,通过then() 进行接受, then() 参数是一个函数,函数的参数就是 resolve传递传递出来的数据

如果Promise()执行失败, 则会调用执行 reject(); reject()中的参数就是执行失败的错误信息, 通过 catch()进行接受, catch的参数一个函数。 函数的参数 err 就是reject 传递出来的错误信息

上实例

<script> 
    var p1 = new Promise(function(resolve, reject){
        if(Math.random() > 0.5){//二分之一的概率成功或失败
            //  执行成功
            // resolve() 会自动调用 then() 中的回调函数, resolve()的参数(数据)就是 then() 中回调函数的接受的数据
            resolve('  成功的结果');
        }else{
            //  执行失败
            // reject() 会自动调用 catch()中的回调函数, reject()的参数(错误信息) 就是catch()中的回调函数接受的数据
            reject('  失败的信息')
        }
    })
    p1.then(function(data){
        console.log('promise 成功执行了' + data);  // promise 成功执行了  成功的结果
    }).catch(function(err){
        console.log('promise 执行失败' + err);  // promise 执行失败  失败的信息
    })
</script>

官方解释

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise()基本结构:
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数; 因为这样, 可以通过Promise() 解决回调地狱的问题

Promise的缺点

● 无法取消Promise,一旦新建它,就会立即执行,无法中途取消
● 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
● 当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

Promise.all()方法

10个ajax请求 全部执行结束 然后在去做下一件事情 ; 如何判断10个请求都执行完成结束了呢?

Promise.all() 方法可以解决这个问题:
接受的参数是一个数组, 数组中的每个值是promise 实例对象, all()的状态是由参数的状态的决定 ; 所有的promise对象都成功则成功,有一个失败则失败

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。(返回的结果是一个新的Promise()对象)

    <script>
        function fun1() {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log('setTimeout1');
                 resolve('setTimeout1 的 data');
                }, 1000)
            })
        }
        function fun2() {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                   console.log('setTimeout2');
                    resolve('setTimeout2 的 data2');
                }, 1500)
            })
        }
        function fun3() {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                   console.log('setTimeout3');
                    resolve('setTimeout3 的 data3');
                }, 2000)
            })
        }
        //  Promise.all() 参数是一个数组, 数组中的每个值都是Ppromise()的实例对象,这里也算是调用 
        const p = Promise.all([fun1(), fun2(), fun3()]);
        //  p 的状态 有 fun1(), fun2(), fun3() 决定,只有fun1(), fun2(), fun3() 都是成功,则 p的 状态是 成功 fulfilled ; 如果  fun1(), fun2(), fun3() 存在一个失败,则 p的状态 是失败rejected
        console.log(p);
        p.then((data) => {
            //  then()方法的回调函数的参数 是 所有 Promise()实例执行成功时传递的数据,自动把所有的数据放到一个数组中
            console.log(data);// (3) ["setTimeout1 的 data", "setTimeout2 的 data2", "setTimeout3 的 data3"]
            console.log('三个函数都执行结束');            
        }).catch((err) => {
            //  catch() 方法 优先捕获失败的信息, 谁先失败 就捕获谁 
            console.log(err);
        });
    </script>

看输出代码
在这里插入图片描述

我们让其一个值状态为失败,看下是不是这样呢

function fun2() {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                   console.log('setTimeout2');  
                    reject('setTimeout2 的 data2');
                }, 1500)
            })
        }

在这里插入图片描述

Promise.race() 方法

Promise.race() 方法 的参数是一个数组, 数组中的每个值是 Promise() 实例对象; 最后返回一个新的Promise() 对象
状态 改变: fun1(), fun2(), fun3() 三个实例对象 谁的状态先改变(不管成功还是失败),则p的状态都会随之跟随改变 如果fun1(), fun2(), fun3() 三个实例对象 先改变的状态是成功,则成功,如果失败就是失败

<script>
    function fun1() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('setTimeout1');
              // resolve('setTimeout1 的 data1  成功');
                 reject('setTimeout1 第一个失败');//因为fun1()的状态先改变失败,所以为失败
            }, 1000)
        })
    }
    function fun2() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('setTimeout2');
               resolve('setTimeout2 的 data2  成功');
              //  reject('setTimeout2 的 失败');
            }, 1500)
        })
    }
    function fun3() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('setTimeout3');
               // resolve('setTimeout3 的 data3  成功');
                reject('setTimeout3 失败了');
            }, 2000)
        })
    }
    //  Promise.race() 方法 的参数是一个数组, 数组中的每个值是 Promise() 实例对象; 最后返回一个新的Promise() 对象
    //  状态 改变: fun1(), fun2(), fun3() 三个实例对象 谁的状态先改变(不管成功还是失败),则p的状态都会随之跟随改变   如果fun1(), fun2(), fun3() 三个实例对象 先改变的状态是成功,则成功,如果失败则失败
    //  
    const p = Promise.race([fun1(), fun2(), fun3()]);
    console.log(p);
    p.then(res => {
        console.log(res);            
    }).catch(err => {
        console.log(err);
    })
</script>

在这里插入图片描述 我们看下先改变的值为成功的情况

function fun1() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('setTimeout1');
              resolve('setTimeout1 的 data1  成功');
            }, 1000)
        })
    }

在这里插入图片描述

async 函数

async/await 的理解和用法

await 是一个修饰符,只能放在async定义的函数内。可以理解为等待。
快速使用例子:

function A() {
        console.log("A执行了");
    };
    function B() {
        console.log("B执行了");
    };
    async function C() {
        await A()
        await B()
    }
    C()

在这里插入图片描述

function A() {
        console.log("A执行了");
    };
    function B() {
        console.log("B执行了");
    };
    async function C() {
        await B()
        await A()
    }
    C()

在这里插入图片描述

加个定时器看执行情况

function A() {
        setTimeout(() => {
            console.log("A执行了");
        }, 1000)
    };
    function B() {
        console.log("B执行了");
    };
    async function C() {
        await A()
        await B()
    }
    C()

1秒钟后A执行
在这里插入图片描述

async 函数 是一个异步操作, 返回的是一个Promise()对象

 async function f() {
        return 'hello world';
    }
    f().then(v => console.log(v))//因为返回是Promise()对象,所以有then方法

await 等待 ; 在 async函数中使用 通常情况下 await 后是一个Promise()对象, 如果不是,会自动转换为Promise()对象

 <script>
    //async 函数 是一个异步操作, 返回的是一个Promise()对象 
 // await 等待 ; 在 async函数中使用   通常情况下 await 后是一个Promise()对象, 如果不是,会自动转换为Promise()对象
  async function fun(val) {
       // console.log(1);
        let res=await fun2();//  await 等待的结果 最终就是一个具体的值, 
        return 'hello  ' + res;
    }
    async function fun2() {
      //  console.log(2);
        return 'world';
    }
    fun().then(function(res){
        console.log(res);//hello  world
    }) 
</script> 
 <script>
    async function fun() {
        let res3 = await new Promise((resolve) => {
            resolve('这是Promise对象');
        })
        return 'hello   ' + res3;//async和await基础.html:39 hello   这是Promise对象
    }
    fun().then(function (res) {
        console.log(res);
    })
</script> 

当Promise()方法 有多个then()时用 async方法

    <script>

        //  基础函数
        function longTime(time) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve(time + 500)
                }, time)
            })
        }
       
        //  三个函数 time1() ==> time2() ===> time3()  通过Promise() 实现
        //  1的输出值2要用,2的输出值3要用,然后输出3的值
     
        function time1(n){
            return longTime(n);//这是一个方法
        }

      /*  time1(500).then(res1 => {
            console.log(res1);//1000
            time1(res1).then(res2 => {
                console.log(res2);//1500
                time1(res2).then(res3 => {
                    console.log(res3);//  2000                  
                })                
            })            
        })

/*    也可以直接用基础函数
        longTime(500).then(res1 => {
            return longTime(res1);
        }).then(res2 => {
            console.log(res2);  1500
            return longTime(res2) ;           
        }).then(res3 => {
            console.log(res3); //2000           
        })*/
    
/* ====上述方法的简写
        time1(500).then(res1 => {
            return time1(res1);
        }).then(res2 => {
           // console.log(res2);  1500
            return time1(res2) ;           
        }).then(res3 => {
            console.log(res3); //2000           
        })
*/
  //  使用 async 函数实现

/*
        async function test(n){
           let res = await longTime(n)
        //    console.log(res);    
            return res;   
        }
        test(500).then(res1 => {
          //  console.log(res1); 
           return longTime(res1)      
        }).then(res2 => {
           // console.log(res2);  
            return longTime(res2)             
        }).then(res3 =>{
            console.log(res3);    //2000        
        })*/


        //  如果存在三个函数这样写
          async function time1(n){ 
               return  await longTime(n)
            }
            async function time2(n){
                return  await longTime(n)
            }
            async function time3(n){   
                return  await longTime(n)
            }
            async function test(n){
                let res1 = await time1(n);
                let res2 = await time2(res1);
                let res3 = await time3(res2);
                console.log(res3); //2000           
            }
            test(500);

    </script>

宏任务和微任务

来源
js 是单线程执行的,js中的任务按顺序一个一个的执行,但是一个任务耗时太长;
那么后面的任务就需要等待,为了解决这种情况,
将任务分为了同步任务和异步任务;

而异步任务又可以分为微任务和宏任务。

宏任务和微任务的分类

宏任务:

setTimeout(定时器每隔多久后执行一次这个函数)

setInterval(定时器只在指定时间后执行一次这个函数)

微任务:

process.nextTick(node.js中的内容)

Promise的then方法

new Promise((r) => {
        console.log("1");//构造函数是同步的(不属于宏任务也不属于微任务)
        r();
    }).then(() => {
        console.log("3");//then()是异步的,这里已经入队
    });
    console.log("2");
    //1
    //2
    //3

在没有async(等待)执行过程是

  • 执行所有同步的,然后执行异步的

  • 存在微任务的话,那么就执行所有的微任务

  • 微任务都执行完之后,执行下一个宏任务

小知识:定时器(宏任务)是最后执行

具体解释在
微任务和宏任务的执行顺序
事件循环中的宏任务和微任务执行顺序

示例:

setTimeout(() => {
    //执行后 回调一个事件
    console.log('事件1')//异步宏任务
}, 0)
console.log('事件2');//同步任务
this.$nextTick(function() {
    console.log('事件3');//异步微任务
})
new Promise((resolve) => {
    console.log('事件4');//同步任务
    resolve()
}).then(() => {
    console.log('事件5');//异步微任务
})

执行顺序是:
在这里插入图片描述
解释:
事件1 setTimeout异步事件,放入异步任务队列;
事件2 所在行是主线程同步,直接执行;
事件3所在行也异步事件,放入异步任务队列;
创建promise的new Promise是主线程,直接执行;
Promise中的then方法为异步函数,放入异步任务队列;

先执行同步,在执行异步(先执行微任务,在执行宏任务)

描述this.nextTick()的用法DOM更新循环之后执行

在组件内使用 vm.$nextTick() 实例方法特别方便,因为它不需要全局 Vue,并且回调函数中的 this 将自动绑定到当前的 Vue 实例上:

Vue.component('example', {
  template: '<span>{{ message }}</span>',
  data: function () {
  		return {
   		 message: '未更新'
  		}
  },
  methods: {
  		 updateMessage: function () {
  		 this.message = '已更新'
   		 console.log(this.$el.textContent) // => '未更新'
  		 this.$nextTick(function () {
   		 console.log(this.$el.textContent) // => '已更新'
   		 })
 	   }
    }
 })

因为 $nextTick() 返回一个 Promise 对象,所以你可以使用新的 ES2017 async/await 语法完成相同的事情:

methods: {
updateMessage: async function () {
 
		this.message = '已更新'
		console.log(this.$el.textContent) // = '未更新'
		await this.$nextTick()
		console.log(this.$el.textContent) // = '已更新'
		}
}

Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。

$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM
【Vue面试题】说说nextTick的使用和原理?

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值