总结JavaScript里面的异步相关知识

目录

一、多线程和异步操作的作用和区别

二、JavaScript是单线程的

三、异步JavaScript的几种实现形式


一、多线程和异步操作的作用和区别

1.作用

两者都是避免线程因为某个任务阻塞而影响程序执行,提高响应速度和执行效率

2.区别

多线程:

        多个线程同时处理任务,每个线程内部的任务还是顺序执行的,缺点就是线程的大量使用会造成系统负担变大,线程之间共享变量可能会造成死锁。

                        Thread1:taskA--->taskB

                        Thread2:taskC--->taskD

异步操作

        异步操作主要是是在程序上这样设计,常常采用回调的方式来处理异步得到的结果,设计编写上会复杂一些

        主线程MainThread执行下面操作

        通俗来讲,主线程执行TaskA,当处理到需要读取数据时,把读取这部分工作交给其他Process,然后自己再执行后面的任务,当Process执行完成时,调用回调函数,然后完成执行TaskA。

        这里的Process可以是DMA(DMA技术使得硬件可以直接访问内存,而不需要依赖于CPU的大量中断负载),也可以是其他线程进行操作。

二、JavaScript是单线程的

        详细可参考:通用异步编程概念 - 学习 Web 开发 | MDN

        JavaScript 传统上是单线程的。即使有多个内核,也只能在单一线程上运行多个任务,此线程称为主线程。

        类比上面的异步操作,Process异步执行过程可以通过 Web workers 可以把一些任务交给一个名为worker的单独的线程,这样就可以同时运行多个JavaScript代码块,一个worker执行一个需要耗时的任务,主线程用于处理交互,这样就避免了阻塞。

三、异步JavaScript的几种实现形式

        详细可参考:异步JavaScript简介 - 学习 Web 开发 | MDN

1.callbacks

        实际上这种老派callbacks异步编程风格就是设置回调函数,等待任务结束后得到某项数据或操作时要执行什么操作。

        (1)比如addEventListener:

    testCallBacks(){
            var btn01 = document.getElementById("btn01");
            btn01.addEventListener('click', () => {
                alert('You clicked me!');

                let pElem = document.createElement('p');
                pElem.textContent = 'This is a newly-added paragraph.';
                document.body.appendChild(pElem);
            });
        }
    },

        其中addEventListener的第二个参数就是一个回调函数,是异步执行的,只有在对button执行click操作时才会执行回调函数,效果如下:

        (2)如果对于异步看的不明显,则可以利用setTimeout来进行测试

        testsetTimeout(){
            setTimeout(()=>{//3s以后执行回调函数
                alert('这是3s之后执行的信息')
            },3000)
           this.testsetTimeoutInfo='0s'
        }

         setTimeout(func,time),第一个参数是回调函数,第二个参数是延迟执行的时间,其实这里并不是严格的time时间后执行,而是在time时间后将任务加到主线程的执行队列中,具体的执行时间还是要看主线程的执行情况。

        从中可以看出改变testsetTimeoutInfo属性发生在setTimeout的回调函数之前,也就是常见的异步操作过程。

2.Promise风格

        Promise是新派异步编程风格代码,其实是把异步过程进行包装,支持更多更高效的操作,其中fetch()就是一个高效的XMLHttpRequest,只需要一个参数——资源的网络 URL,然后返回一个 promise。promise 是表示异步操作完成或失败的对象。可以说,它代表了一种中间状态。

        Promise是专门为异步操作而设计的,与旧式回调相比具有许多优点

        Promise可以利用then形成链式执行,将多个异步操作串联起来,把一个操作的结果作为输入传递到下一个操作中,可以将错误放到catch里面进行处理,错误处理更加方便。Promise.all可以将任务数组作为参数,清楚的知道这些任务的执行结果,然后针对这些结果进行下一步操作。

(1)Promise包装异步过程

    testpromise(){
            let newpromise=new Promise((resolve,reject)=>{
                setTimeout(() => {
                    resolve('0.3s中后执行');
                }, 300);
            })

            newpromise.then((value)=>{
                console.log(value)
                setTimeout(() => {
                    console.log('0.6s中后执行');
                }, 300);
            })
            console.log('0s后执行')
        }

 (2)Pormise.all(taskarr)

        当taskarr任务全部执行完后才会执行console.log(val)

    testpromiseAll(){
            let newpromise1=new Promise((resolve,reject)=>{
                setTimeout(() => {
                    console.log('0.1s中后执行')
                    resolve('0.1s中后执行');
                }, 100);
            })
            let newpromise2=new Promise((resolve,reject)=>{
                setTimeout(() => {
                    console.log('0.2s中后执行')
                    resolve('0.2s中后执行');
                }, 200);
            })
            let newpromise3=new Promise((resolve,reject)=>{
                setTimeout(() => {
                    console.log('0.3s中后执行')
                    resolve('0.3s中后执行');
                }, 300);
            })
            let promiseArr=[newpromise1,newpromise2,newpromise3]

            Promise.all(promiseArr).then((val)=>{
                console.log(val)
            })
        }

3.通过时间推迟执行代码实现异步

        详细可参考:合作异步JavaScript: 超时和间隔 - 学习 Web 开发 | MDN

 (1)setTimeout()

        [指定时间后执行一段代码,上面已经使用到了]

        要注意一下时间间隔参数,(即使是0时)并不是立刻执行,指定的时间(或延迟)不能保证在指定的确切时间之后执行,而是最短的延迟执行时间。在主线程上的堆栈为空之前,传递给这些函数的回调将无法运行。

        testsetTimeout0(){
            setTimeout(()=>{
                console.log('设置setTimeout的参数time=0')
            },0)
            for(let idx=0;idx<5;idx++){
                console.log(idx)
            }
        }

(2)setInterval()

        [以固定时间间隔,重复执行一段代码]

    let i = 1;
    setInterval(function run() {
    	console.log(i);
    	i++
    }, 100);

        注意:如果run()函数执行了40ms,则在执行完成60ms以后将执行下一次的run函数

        如果想要严格的每100ms执行一次run则可以采用递归setTimeout()的方式实现:

        testsetTimeout1(){//递归setTimeout()
            let i = 1;
            setTimeout(function run() {
                console.log(i);
                i++;
                if(i<20){
                    setTimeout(run, 100);
                }
            }, 100);
        },

4.async/await

        其实async和await是基于promise的语法糖,本质上还是promise,使异步代码更易于编写和阅读。通过使用它们,异步代码看起来更像是老式同步代码。

        使用 async 关键字,把它放在函数声明之前,使其成为 async function。异步函数是一个知道怎样使用 await 关键字调用异步代码的函数,async修饰的函数返回值是promise

        需求:“await执行完成以后才会打印”这句话在3s后执行之后打印

        (1)如果不使用await的效果

        getpromise(){ 
            let newpromise=new Promise((resolve,reject)=>{
                setTimeout(() => {
                    console.log('3s后执行')
                    resolve('3s后执行');
                }, 3000);
            })
            return newpromise
        },
        testAsyncAndAwait(){
             this.getpromise()
            console.log("await执行完成以后才会打印")
        }

         下面使用async/await修饰以后(符合要求)

        getpromise(){
            let newpromise=new Promise((resolve,reject)=>{
                setTimeout(() => {
                    console.log('3s后执行')
                    resolve('3s后执行');
                }, 3000);
            })
            return newpromise
        },
        async testAsyncAndAwait(){
            await this.getpromise()
            console.log("await执行完成以后才会打印")
        }

         完全可以通过调用 await Promise.all() 将所有结果返回到变量中,就像同步代码一样,避免了then的调用,更简洁了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值