你必须要了解的异步

前言

总所周知,javascript是单线程运行的,并没有多线程运行这么一说,那为什么会有异步进行的说法呢。 这里就要纠正一个概念,异步和多线程并行是不同的,异步只是在现在和将来之间进行切换,并不是代表着多线程同时运行。

正文

什么是js异步

在javascript中,异步的概念只是说将现在要发生的事情,放到将来去运行,做为单线程程序,在同一时间只会运行一个主程序代码,不会存在多个经常在同时运作,就不会有多进程的编写,那么,这么说的话,js的异步究竟是如果进行的呢,接下来慢慢分析

回调函数

回调在一定程度上能够代表着异步进程,因为大多数内容都是可以通过回调进行异步,例如ajax,使用ajax之后,我们会提供一个回调函数,然后在一定时间后浏览器会响应我们的回调函数,那么,具体操作是什么呢?

当然这里可能不是浏览器,也可能是其他的宿主对象,我就暂时以浏览器的内容做一个简单的介绍(后续文章会对回调做一个完整的介绍)

  1. 首先我们发送了ajax请求,然后通知了我们的浏览器,我需要暂停这个服务了,因为这个时候还在等待期间,如果,ajax不暂停,而在一直等待的话,那么我们整个服务就卡在那边需要等待ajax请求结束才能在继续使用,所以,在这个时候,它会告诉浏览器,你等这个http请求返回了结果,你就去调用我给你看的这个函数
  2. 浏览器收到了这个请求,然后就不去等待ajax的返回,接下去执行另一段代码
  3. 等http返回了内容,浏览器终于知道了,你服务好了,那我要去调用这个方法了,但是我们也说过,js是单线程的,不可能会因为这个事件好了,那我就停下来当前的事情,先去处理这个返回,所以这里就涉及到了我们的js事件循环
事件循环(event loop)

event loop其实分为两种,一种是在浏览器端的事件循环,一种是在服务器端的(nodejs),这里我们只介绍浏览器层次的内容,关于nodejs的event loop在后续的学习中,会陆续介绍。

在事件循环中,js在运行的时候,会生成一个任务队列,循环去执行,任务分为两种任务进度,宏任务跟微任务

宏任务(task)

js运行的主任务,每次执行完当前的task内全部任务,就会去重新渲染一边页面内容, task内容包括:

  1. 主js流程代码块
  2. dom的click等响应事件
  3. settimeout产生的异步事件
  4. ...
微任务 (Microtasks)

microtasks 运行在task之后,每次当前的task内部任务完成之后,会立即去执行microtasks内部的任务,然后再进行新的一轮task的任务队列,microtasks包括:

  1. promise回调
  2. mutation observe回调
  3. ...
简单的案例
function a(){
    console.log(1);
    Promise.resolve().then(function(res){
        console.log(2);
    })
    setTimeout(function(){
        console.log(4);
        Promise.resolve().then(function(res){
            console.log(5);
        })
        console.log(6);
    })
    console.log(3);

}
复制代码

那么这个案例会怎么输出呢,答案是1,3,2,4,6,5。

不知道大家猜到了没有,按照先前的叙述,浏览器会先运行a方法里面的主流程,即打印出1,3,然后将第一个promise放进下一个微任务,将settimeout放入下一个宏任务,当第一个宏任务结束的时候,就会执行了下一个微任务就是第一个promise,等第一个promise运行结束之后又会重新开始后续的宏任务队列,由于第二个promise是在settimeout中执行的,所以只有当第二次宏任务执行的时候,才会将第二个promise放入微任务队列,所以我们能够很轻易的得出答案就是132465.

这就是js在执行异步操作的时候会执行的整个过程,接下来我们来了解了解,并行是一个什么样的过程

并行

其实在我看来,并行是属于异步的一种分支,因为并行本质上是多条内容在同步执行,但是,既然鉴于我们之前了解的js是一个单线程运行程序,那为什么会有并行这么一说呢。

什么是并行

其实js中的并行,更详细点讲,就是多个http请求同时发出,浏览器等待回应。因为js本身在浏览器中是不支持多线程运行的,但是并不阻挡js监听http返回的内容。所以当我们加载页面的时候,多个请求同时发送,就构成了广义上的并行

并行会有什么问题
  • 无法确定回调顺序
  • 对相同数据进行处理会产生覆盖或修改操作
如何解决
  1. 对于必须要的请求,如果对相同数据做操作,放进回调后再去调用
  2. 为了避免回调地狱,可以用async 跟 await进行回调写法
  3. 并行加载初始化数据,不要让返回的内容,输入在同一个变量中
  4. 对多个请求,只获取其中一个数据的,可以设置门闩,拿第一个或者最后一个,或者确定的一个数据源

总结

对于js异步,其实是一个任务队列的不断循环操作,不管是回调还是监听,实际上都是放在任务队列中,然后通过事件循环不断的去调用,触发,希望对你们有所用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值