实例分析javascript中的异步

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异步具体执行流程分析

大家看一下左边代码,两个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 异步的资料请关注我们其它相关文章!

(0)

相关推荐

  • JS异步处理的进化史深入讲解

    前言 javascript是一门单线程的语言,也就是说一次只能完成一件任务,如果有多个任务,就需要排队进行处理.如果一个任务耗时很长,后面的任务也必须排队等待,这样大大的影响了整个程序的执行.为了解决这个问题,javascript语言将任务分为两种模式: 同步:当我们打开网站,网页的页面骨架渲染和页面元素渲染,就是一大推同步任务. 异步:我们在浏览新闻时,加载图片或音乐之类占用资源大且耗时久的任务就是异步任务. 本文主要针对近两年javascript的发展,主要介绍异步处理的进化史.目前,在ja

  • 浅析JavaScript异步代码优化

    前言 在实际编码中,我们经常会遇到Javascript代码异步执行的场景,比如ajax的调用.定时器的使用等,在这样的场景下也经常会出现这样那样匪夷所思的bug或者糟糕的代码片段,那么处理好你的Javascript异步代码成为了异步编程至关重要的前提.下面我们从问题出发,一步步完善你的异步代码. 异步问题 1. 回调地狱 首先,我们来看下异步编程中最常见的一种问题,便是回调地狱.它的出现是由于异步代码执行时间的不确定性及代码间的依赖关系引发的,比如: // 一个动画结束后,执行下一个动画,下一个

  • js前端面试之同步与异步问题详解

    前言 我本来是打算写一篇co源码精读(为啥读co,因为它短),然鹅发现自己存在一系列基础问题没有搞透彻,打算写一个js基础系列文章,总结自己的理解(copy),希望与你在学习路上一同进步.首先问问自己当面试官问到js中的同步和异步,这个问题该怎么回答?理解一个问题无非是what-why-how js同步和异步问题是什么-->为什么会产生异步问题-->如何解决. 一.JavaScript起源 技术的出现,和应用场景密切相关的.JavaScript诞生于1995年.当时,它的主要目的是处理以前由服

  • 单线程JavaScript实现异步过程详解

    前两天硬着头皮在部门内部做了一次技术分享,主题如题.索性整理成文章留个纪念! 要了解异步实现,首先我们得先了解: 同步 & 异步 同步:会逐行执行代码,会对后续代码造成阻塞,直至代码接收到预期的结果之后,才会继续向下执行任务. 异步:调用之后先不管结果,继续向下执行任务. 网上各种文章对同步和异步的解释也不外如是,但是看文字总是有点晦涩难懂!我就生活化的来比拟一下这两个概念吧! 就好比请人吃饭: 比如你要请两个人吃饭,一个是巴菲特,由于他是举世瞩目股神想请他吃饭的人从这里排到了法国,你为表诚意,

  • 实例分析javascript中的异步

    js 异步解析 一 .js单线程分析 我们都知道js的一大特点是单线程,也就是同一时间点,只能处理一件事,一句js代码.那为什么js要设计成单线程而不是多线程呢?这主要和js的用途有关,js作为浏览器端的脚本语言,主要的用途为用户与服务端的交互与操作dom.而操作dom就注定了js只能是单线程语言.假如js才取多线程将会出现,多个线程同时对一个dom进行操作的情况,浏览器将无法判断如何渲染.不仅js是单线程,浏览器渲染dom也是单线程的,js的执行和浏览器渲染dom共用的一个线程,这就导致了在h

  • 实例分析javascript中的call()和apply()方法

    1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call 方法可以用来代替另一个对象调用一个方法.call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象. 如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj. apply方法: 语法:apply([thisObj[,argArray]])

  • 详细分析Javascript中创建对象的四种方式

    前言 使用Javascript创建对象的方式有很多,现在就来列举一下其中的四种方式,并且罗列出了每种方式的优缺点,可以让大家进行选择使用,下面来看看. 工厂模式 function createPerson(name, age){ var obj = new Object(); obj.name = name; obj.age = age; return obj; //一定要返回,否则打印undefined:undefined } var person1 = new createPerson('Y

  • 如何在现代JavaScript中编写异步任务

    前言 在本文中,我们将探讨过去异步执行的 JavaScript 的演变,以及它是怎样改变我们编写代码的方式的.我们将从最早的 Web 开发开始,一直到现代异步模式. 作为编程语言, JavaScript 有两个主要特征,这两个特征对于理解我们的代码如何工作非常重要.首先是它的同步特性,这意味着代码将逐行运行,其次是单线程,任何时候都仅执行一个命令. 随着语言的发展,允许异步执行的新工件出现在场景中.开发人员在解决更复杂的算法和数据流时尝试了不同的方法,从而导致新的接口和模式出现. 同步执行和观察

  • 分析javascript中9 个常见错误阻碍你进步

    分析javascript中9 个常见错误阻碍你进步 很多人尝试学习 JavaScript ,但是不久就放弃了.然后他们就告诉自己,"JavaScript 太复杂了",更有甚者说,"我不是前端开发的料". 这种情况挺让人悲伤的.其实根本不必放弃,所要做的仅仅是换一种不同的学习方法. 在这篇文章中,我们将介绍一些最常见的错误学习方法,并了解如何避免这些错误.许多技巧不仅适用于 JavaScript,甚至可以用到 web 开发上,所以也算是一种福利. 我们来吧! 错误 #

  • 详细分析JavaScript中的深浅拷贝

    在说JS中深浅拷贝之前,我们需要对JS中的数据类型有所了解,分为基本数据类型与引用数据类型,对于基本数据类型并没有深浅拷贝的说法,深浅拷贝主要针对引用数据类型. 一.浅拷贝 浅拷贝只复制了引用,并没有复制值.在JS中最简单的浅拷贝就是利用"="赋值操作符来实现. var obj1 = { a:1, b:[2,3,4], c:{name:'tanj'}, fun:function(){ console.log('fun') } } var obj2 = obj1 obj2.a = 666

  • JavaScript中的异步能省掉await吗?

    之前我知道要在JavaScript中同步获取异步执行的结果,必须带await;在for循环中,如果不用Promise.All的话,异步不起效果.但是每次需要等待执行结果的时候,都需要带async和await,我觉得老麻烦了,也不好看.如果记住了这两个单词的写法倒还好,没记住的话每次拼错,能把思路打断,忽然冒出这样的单词,也不美观. 于是我就一致致力于解决这个问题,作为一个经常以造轮子为自豪的程序员,我认为我有责任为JavaScript的改变做出一点小小的贡献. 请看下面这段代码: const t

  • 实例分析浏览器中“JavaScript解析器”的工作原理

    浏览器在读取HTML文件的时候,只有当遇到<script>标签的时候,才会唤醒所谓的"JavaScript解析器"开始工作. JavaScript解析器工作步骤: 1."找一些东西": var. function. 参数:(也被称之为预解析) 备注:如果遇到重名分为以下两种情况: 遇到变量和函数重名了,只留下函数 遇到函数重名了,根据代码的上下文顺序,留下最后一个 2.逐行解读代码. 备注:表达式可以修改预解析的值 JS解析器在执行第一步预解析的时候,会

  • 深入浅出分析javaScript中this用法

    本文实例讲述了javaScript中this用法.分享给大家供大家参考.具体分析如下: 之前学javascript的时候总搞不清this,这个this不像java里的this那么好理解.我后来也是看了许多别人写的文章,才理解过来的.现在把别人写的东西搬过来,怕以后忘记. 总得来说 this的指向分三种.指向全局window,该对象,构造函数. 结论:在Javascript中,this指向函数执行时的当前对象.  简单点说就是调用的方法属于哪个对象,this就指向那个对象. 1. 全局window

  • 实例讲解JavaScript中instanceof运算符的用法

    instanceof 运算符简介 在 JavaScript 中,判断一个变量的类型尝尝会用 typeof 运算符,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 "object".ECMAScript 引入了另一个 Java 运算符 instanceof 来解决这个问题.instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型.与 typeof 方法不同的是,instanceof 方法要求开发者明确地确

随机推荐