浅谈JS异步(asychrouous)

一、概念

(1)asychronous 异步
是JS这种单线程语言解决多任务的一种方法,将耗时的任务(io)设定为异步工作,先交给浏览器负责相关功能的线程来实现耗时的部分工作,按顺序放入任务队列中,等待主代码执行完成,而主线程继续下一个任务,不阻塞代码;主线程任务完成后,会收到浏览器的通知,来实现异步任务的其他代码执行
===>事件循环+任务队列

(2)sychronous 同步

任务的执行是一个接着一个执行的,上一个任务执行完成才能继续下一个任务,有多个窗口,进行一个接一个的执行任务

二、异步有序问题

1、回调=====>回调地狱

当我们需要进行有序任务时,最粗暴的方式就是用时间函数嵌套,少个还可以分辨,但若出现上百、上千个事件呢?如果任然使用这种方法,就会形成“回调地狱”,没有办法阅读处时间函数的时间对应的代码是哪一个,不利于后续的维护:

setTimeout(function () {
            console.log("a");
            setTimeout(function () {
                console.log("b");
                setTimeout(function () {
                    console.log("c");
                    setTimeout(function () {
                        console.log("d");
                    }, 1000)
                }, 2000)
            }, 1000)
        }, 1000)

于是乎,我们的先人们捣鼓出了专门处理异步的方法。

2、Promise 构造函数

首先,我们来看一看使用Promise 构造函数与上面的代码有什么不同

        new Promise(function (resolve, reject) {
            // console.log("a1");
            setTimeout(function () {
                console.log("a");
                resolve();
            }, 1000)
        }).then(() => {
            // return 1;//下一个then被处罚时可以接收返回值

            return new Promise(function (resolve, reject) {
                // console.log("b1");
                setTimeout(function () {
                    console.log("b");
                    resolve();
                }, 2000)
            })
        }).then((data) => {
            return new Promise(function (resolve, reject) {
                // console.log("c1");
                setTimeout(function () {
                    console.log("c",data);
                    resolve();
                },3000)
            })
        })

我们可以看到,Promise让每一个异步都是平行的了,不再是嵌套关系,语义化非常强,让人一眼可以看出每个事件发生的顺序。

(1)使用Promise要注意状态值:

  • pending   已就绪, Promise实例化的同时就已就绪,状态只可改变1次,且不可逆
  • resolved/fulfilled   已完成
  • rejected   已失败

===>状态改变,then方法会触发onfulfilled,onrejected事件

(2)Promise构造函数

我们分步骤来看,是怎样应用的:

new Promise(function(resolve,reject){});
//两个形参:resolve reject ,都是回调函数
 let fn1;
 let fn2;
new Promise(function(resolve,reject){//两个形参,都是回调函数
       resolve();
       fn1 = resolve;
       fn2 = reject;
});            

resolve()方法会返回已完成状态,就会触发onfulfilled事件,让then()代码走下去

若要写异步函数,则将第一个异步函数写在Promise里面,之后每一个任务可以使用then()来触发,每个then()只能完成一个任务

 p.then((data)=>{//参数为2个事件监听器,第一个是已成功时触发,第二个是以失败时触发
        console.log("onfulfilled",data);
},(data)=>{
         console.log("onrejected",data);//onrejected 触发且异常,不报错
  })

 console.log(p);

then :

  • 返回值为promise对象,初始状态是pending
  • 监听器被触发,监听函数执行完成后,返回值的状态发生改变
  • 改变的情况由监听函数的执行返回值决定,而具体情况参照Promise.resolve(返回值)

then(onfulfilled,onrejected)含有两个参数,都是事件监听器(函数),第一个是已成功时触发,第二个是以失败时触发。onrejected 触发且异常时,不报错。

整体的代码就是:

 let fn1;
            let fn2;
        let p = new Promise(function(resolve,reject){//两个形参,都是回调函数
            resolve();
            //第一个异步函数放在Promise里
            fn1 = resolve;
            fn2 = reject;
        });

        p.then((data)=>{//参数为2个事件监听器,第一个是已成功时触发,第二个是以失败时触发
            console.log("onfulfilled",data);

        },(data)=>{
            console.log("onrejected",data);//onrejected 触发且异常,不报错
        })

        console.log(p);

(3)all(),race()

在Promise中有两个好用的方法,就是 all(),race()

  • all()方法:在所有异步代码都跑了后,同时输出结果,但结果显示顺序根据异步事件结束的先后来的
     let p1 = new Promise(function (resolve, reject) {
            console.log("a开始了");
            
            setTimeout(function () {
                console.log("a");
                resolve();
            }, 4000)
        })
        let p2 = new Promise(function (resolve, reject) {
            console.log("b开始了");
            setTimeout(function () {
                console.log("b");
                resolve();
            }, 3500)
        })
        let p3 = new Promise(function (resolve, reject) {
            console.log("c开始了");
            setTimeout(function () {
                console.log("c");
                resolve();
            }, 5000)
        })

        let pp = Promise.all([p1,p2,p3]);
        pp.then(()=>{
            console.log("all");
            
        })

 

  • race()方法:赛跑,谁先结束谁先输出
        let p1 = new Promise(function (resolve, reject) {
            console.log("a开始了");
            
            setTimeout(function () {
                console.log("a");
                resolve();
            }, 4000)
        })
        let p2 = new Promise(function (resolve, reject) {
            console.log("b开始了");
            setTimeout(function () {
                console.log("b");
                resolve();
            }, 3500)
        })
        let p3 = new Promise(function (resolve, reject) {
            console.log("c开始了");
            setTimeout(function () {
                console.log("c");
                resolve();
            }, 5000)
        })

        // let pp = Promise.all([p1,p2,p3]);
        // pp.then(()=>{
        //     console.log("all");
            
        // })
        
        pp = Promise.race([p1,p2,p3]);
        pp.then(()=>{
            console.log("race");
            
        })

 b时间最短,因此是b获胜

all、race 都生成promise对象,但是状态的变化情况不一样

(4)返回值 return

Promise.value 通过resolve传递的参数

Promise.reslove(value)方法,返回一个以给定值解析后的Promise对象
value有三种情况:

  1. 普通值:除了promise对象,和thenable对象的所有值,生成一个已完成的promise对象并且PromiseValue的值就是传入的value
  2. promise对象,直接返回该value
  3. thenable对象,参照new Promise 生成的promise对象,其中then方法就好比new Promise(cb)中的cb

在then(data)中,data就是value的值,我们回到开头的那段代码:

new Promise(function (resolve, reject) {
            // console.log("a1");
            setTimeout(function () {
                console.log("a");
                resolve();
            }, 1000)
        }).then(() => {
            // return 1;//下一个then被处罚时可以接收返回值

            return new Promise(function (resolve, reject) {
                // console.log("b1");
                setTimeout(function () {
                    console.log("b");
                    resolve();
                }, 2000)
            })
        }).then((data) => {
            return new Promise(function (resolve, reject) {
                // console.log("c1");
                setTimeout(function () {
                    console.log("c",data);
                    resolve();
                },3000)
            })
        })
then(() => {
            // return 1;//下一个then被处罚时可以接收返回值,大家可以自己去试一试。

 

 

 

 

posted @ 2019-12-15 21:16  袁钧钧  阅读(557)  评论(0编辑  收藏  举报