实例分析javascript中的异步


Posted in Javascript onJune 02, 2020

js 异步解析

一 、js单线程分析

     我们都知道js的一大特点是单线程,也就是同一时间点,只能处理一件事,一句js代码。那为什么js要设计成单线程而不是多线程呢?这主要和js的用途有关,js作为浏览器端的脚本语言,主要的用途为用户与服务端的交互与操作dom。而操作dom就注定了js只能是单线程语言。假如js才取多线程将会出现,多个线程同时对一个dom进行操作的情况,浏览器将无法判断如何渲染。不仅js是单线程,浏览器渲染dom也是单线程的,js的执行和浏览器渲染dom共用的一个线程,这就导致了在html代码中书写js代码会造成浏览器端渲染的阻塞。例如:在html某个位置,写一个段带有alert(‘稍等'),alert 之前html已经被渲染出来,而alert之后的html被这段js阻塞了。为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完 全受主线程控制,且不可进行DOM操作。所以,这个新标准并没有改变JavaScript单线程的本质。

     所谓的js单线程,是指在浏览器中JS引擎负责解释和执行JavaScript代码的线程只有一个。不妨叫它主线程。但是实际上浏览器处理js还存在其他的线程。例如:处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程(例如在Node.js中)等等。这些线程可能存在于JS引擎之内,也可能存在于JS引擎之外,在此我们不做区分。不妨叫它们工作线程

     总结一下:js之所以才取单线程模式是为了避免DOM渲染冲突。而浏览器中执行js线程是单线程我们称它为主线程,同时还存在其它处理js的线程,我们称它为工作线程。js是单线程,但浏览器是多线程的。

二 、同步与异步

     单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。这就是同步代码阻塞。如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。

     简单的说,同步就是会阻塞代码的执行,而异步不会。同样拿alert('稍等') 来举例,在一段js代码中加入一段alert,如果没有点击确认,此时代码的执行就被阻塞了,大多数js代码都是同步执行的。异步则相反。那为什么js中要引入异步的概念呢,很简单,由于js的单线程,当遇到耗时的操作时如果采用同步的执行,那么我们就不可能看到如今这么流畅的web应用了。再举个简单的例子:在一条单行道上行驶着很多汽车,假如其中某一辆车出现机械故障,将会导致后面的车也无法通过,此时应该将故障的车拉入旁边的应急车道进行修复,待它修好之后再重新驶入主干道中,不会影响主干道其它行驶的汽车。所以,异步是js单线程下解决耗时问题的一种“无可奈何”的解决方案。也是一种近乎完美的解决方案。

三、js异步与事件轮询

     事件轮询(event loop)是js异步的实现方式。简而言之,在js单线程中分为两种任务,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入”任务队列”(task queue)的任务,只有当主进程中所有同步任务执行完毕,且”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。事件轮询就是将主线程中的异步任务挂载到任务队列中,再待到合的时机,将任务队列中的异步函数拉到主进程来执行的这么一个流程。

js中异步操作主要有:

     1、定时任务(setTimeout、setInterval)

     2、网路请求(ajax、动态<img>加载)

     3、事件绑定(click,focus,change等)

 js异步具体执行流程分析

实例分析javascript中的异步

     大家看一下左边代码,两个console.log操作,两个setTitmeout 操作。按照我们对异步的理解,在主线程中 console.log 为同步任务从上到下依次执行,所以在最先打印的是3,当执行到第一setTimeout时,浏览器js引擎会自动将setTimeout放入工作线程中。ps:在工作线程中,待0.1s后将setTimeout 的回调函数放入异步队列中;主进程中下一个setTimeout ,但是它的延迟时间为0,这并不意味着它能同步执行,它依旧经历如上两个过程,从工作进程中,0s后放入任务队列。接下来是执行console.log(3);当主进程中任务已经执行完毕。任务队列中有一个监视器,随时监视着主进程和任务队列中的异步函数情况,当主进程执行完毕,就判断任务队列中是否有需要执行的函数,如果有就按照队列现后顺序依次放入主进程中,以此往复。

     所以上面代码,依次打印为:3,3,2,1。也就是先将非异步执行完,再回过头来执行异步函数,异步函数执行顺序为队列规则,先进先出,也就是先进入队列的异步函数将优先执行。

     思考:如果一段代码中现后存在一个ajax 和一个1s的定时函数,那么他们谁先执行呢? 答案是:不确定。因为不确定ajax请求完毕进入队列的时间。小伙伴们可别被面试管套路了哦。哈哈。

四、前端异步的写法

     1、回调函数,也就是在setTimeout或者ajax中添加回调函数,待到指定时间后或者请求到数据后再执行回调。

     2、ES6标准:Promise,ES7:async await   这两种都只是js事件轮询实现异步的一种优雅的 方式,将异步变为同步的写法,但都并未改变js异步本质。

以上就是实例分析javascript中的异步的详细内容,更多关于javascript 异步的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JQuery获取浏览器窗口内容部分高度的代码
Feb 24 Javascript
jquery如何通过name名称获取当前name的value值
Dec 20 Javascript
jQuery实现的导航条切换可显示隐藏
Oct 22 Javascript
在Mac OS下使用Node.js的简单教程
Jun 24 Javascript
AngularJS 实现JavaScript 动画效果详解
Sep 08 Javascript
Bootstrap基本组件学习笔记之input输入框组(9)
Dec 07 Javascript
jQuery插件FusionCharts绘制的2D条状图效果【附demo源码】
May 13 jQuery
详解Angular 中 ngOnInit 和 constructor 使用场景
Jun 22 Javascript
js原生日历的实例(推荐)
Oct 31 Javascript
jQuery实现新闻播报滚动及淡入淡出效果示例
Mar 23 jQuery
详解Vue中使用插槽(slot)、聚类插槽
Apr 12 Javascript
解决Vue 刷新页面导航显示高亮位置不对问题
Dec 25 Javascript
vue + node如何通过一个Txt文件批量生成MP3并压缩成Zip
Jun 02 #Javascript
js简单实现自动生成表格功能示例
Jun 02 #Javascript
JS中准确判断变量类型的方法
Jun 01 #Javascript
Vuex中的Mutations的具体使用方法
Jun 01 #Javascript
vue使用自定义事件的表单输入组件用法详解【日期组件与货币组件】
Jun 01 #Javascript
Bootstrap table 服务器端分页功能实现方法示例
Jun 01 #Javascript
easyUI 实现的后台分页与前台显示功能示例
Jun 01 #Javascript
You might like
php 伪造ip以及url来路信息方法汇总
2014/11/25 PHP
在WordPress中实现评论头像的自定义默认和延迟加载
2015/11/24 PHP
浅析Yii2 GridView 日期格式化并实现日期可搜索教程
2016/04/22 PHP
分析PHP中单双引号的误区和双引号小隐患
2016/07/19 PHP
PHP实现根据数组某个键值大小进行排序的方法
2018/03/13 PHP
潜说js对象和数组
2011/05/25 Javascript
使用Mootools动态添加Css样式表代码,兼容各浏览器
2011/12/12 Javascript
JavaScript1.6数组新特性介绍以及JQuery的几个工具方法
2013/12/06 Javascript
confirm的用法示例用于按钮操作时确定是否执行
2014/06/19 Javascript
JQuery的Ajax中Post方法传递中文出现乱码的解决方法
2014/10/21 Javascript
JS实现同时搜索百度和必应的方法
2015/01/27 Javascript
JQuery中$.each 和$(selector).each()的区别详解
2015/03/13 Javascript
JavaScript弹出新窗口后向父窗口输出内容的方法
2015/04/06 Javascript
vue引入swiper插件的使用实例
2017/07/19 Javascript
vue学习笔记之v-if和v-show的区别
2017/09/20 Javascript
基于angular-utils-ui-breadcrumbs使用心得(分享)
2017/11/03 Javascript
JavaScript树的深度优先遍历和广度优先遍历算法示例
2018/07/30 Javascript
vue动画之点击按钮往上渐渐显示出来的实例
2018/09/29 Javascript
浅谈发布订阅模式与观察者模式
2019/04/09 Javascript
jQuery利用cookie 实现本地收藏功能(不重复无需多次命名)
2019/11/07 jQuery
高效jQuery选择器的5个技巧实例分析
2019/11/26 jQuery
vue使用video插件vue-video-player详解
2020/10/23 Javascript
[01:17]Ti4 循环赛第一日回顾
2014/07/11 DOTA
python 基于TCP协议的套接字编程详解
2019/06/29 Python
python交互模式下输入换行/输入多行命令的方法
2019/07/02 Python
python实现中文文本分句的例子
2019/07/15 Python
PyQt5基本控件使用详解:单选按钮、复选框、下拉框
2019/08/05 Python
Python 调用有道翻译接口实现翻译
2020/03/02 Python
HTML5实现简单图片上传所遇到的问题及解决办法
2016/01/20 HTML / CSS
Geekbuying波兰:购买中国电子产品
2019/10/20 全球购物
平安工地建设方案
2014/05/06 职场文书
护士优质服务演讲稿
2014/08/26 职场文书
写给领导的感谢信
2015/01/22 职场文书
销售开票员岗位职责
2015/04/15 职场文书
2015年计算机教学工作总结
2015/07/22 职场文书
2015年库房管理工作总结
2015/10/14 职场文书