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 异步解析的更多相关文章

  1. 深入解析Javascript异步编程

    这里深入探讨下Javascript的异步编程技术.(P.S. 本文较长,请准备好瓜子可乐 :D) 一. Javascript异步编程简介 至少在语言级别上,Javascript是单线程的,因此异步编程 ...

  2. Javascript 异步加载详解

    Javascript 异步加载详解 本文总结一下浏览器在 javascript 的加载方式. 关键词:异步加载(async loading),延迟加载(lazy loading),延迟执行(lazy ...

  3. JavaScript异步编程

    前言 如果你有志于成为一个优秀的前端工程师,或是想要深入学习JavaScript,异步编程是必不可少的一个知识点,这也是区分初级,中级或高级前端的依据之一.如果你对异步编程没有太清晰的概念,那么我建议 ...

  4. [转]JavaScript异步机制详解

    原文: https://www.jianshu.com/p/4ea4ee713ead --------------------------------------------------------- ...

  5. 【JS】368- 浅析JavaScript异步

    一直以来都知道 JavaScript是一门单线程语言,在笔试过程中不断的遇到一些输出结果的问题,考量的是对异步编程掌握情况.一般被问到异步的时候脑子里第一反应就是 Ajax, setTimseout. ...

  6. 浅析JavaScript异步

    一直以来都知道JavaScript是一门单线程语言,在笔试过程中不断的遇到一些输出结果的问题,考量的是对异步编程掌握情况.一般被问到异步的时候脑子里第一反应就是Ajax,setTimseout...这 ...

  7. 简述javascript的解析与执行

    我们知道浏览器中javascript程序的执行是基于变量与函数的.那么浏览器是如何保存数据,又是如何执行的呢?今天我们一起来探究一下! 0.写在前 最新的 ECMAScript 标准定义了 8 种数据 ...

  8. JavaScript异步编程的主要解决方案—对不起,我和你不在同一个频率上

    众所周知(这也忒夸张了吧?),Javascript通过事件驱动机制,在单线程模型下,以异步的形式来实现非阻塞的IO操作.这种模式使得JavaScript在处理事务时非常高效,但这带来了很多问题,比如异 ...

  9. JavaScript异步编程原理

    众所周知,JavaScript 的执行环境是单线程的,所谓的单线程就是一次只能完成一个任务,其任务的调度方式就是排队,这就和火车站洗手间门口的等待一样,前面的那个人没有搞定,你就只能站在后面排队等着. ...

随机推荐

  1. VS2010 Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)

    步骤如下: 1. Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)" title="VS2010 Chart控件(一)Chart控件在ASP.NE ...

  2. selenium下打开Chrome报错解决

    错误如下: [22516:20196:0704/024642.979:ERROR:install_util.cc(597)] Unable to read registry value HKLM\SO ...

  3. python学习笔记(四)- 常用的字符串的方法

    一.常用的字符串方法(一):(字符串是不能被修改的) 1)a.strip()   #默认去掉字符串两边的空格和换行符 a = ' 字符串 \n\n ' c = a.strip() a.lstrip() ...

  4. Pandas聚合

    数据聚合 import pandas as pd from pandas import Series import numpy as np # 准备数据 df = pd.DataFrame([[-0. ...

  5. 迭代器模块 itertools

    无限迭代器 itertools 包自带了三个可以无限迭代的迭代器.这意味着,当你使用他们时,你要知道你需要的到底是最终会停止的迭代器,还是需要无限地迭代下去. 这些无限迭代器在生成数字或者在长度未知的 ...

  6. canvas(二) lineCap demo

    var dom = document.getElementById('clock'), ctx = dom.getContext('2d'); ctx.beginPath(); ctx.moveTo( ...

  7. Vue 的生命周期图

  8. Python 多个分隔符 读取逗号和空格分开的数据

    str.split()  清除默认 空格和tab  对空格数量不敏感 str.split(' ') 只清除一个空格     对空格数量敏感 l = re.split('[^0-9.]+',s.stri ...

  9. Maven学习 一 概念介绍

    一 Maven是什么 Maven是一个Apache公司的开源项目,主要有两个作用:(1)是项目构建工具.(2)是用来管理java程序中jar包的依赖. 它包含了一个项目对象模型(Project Obj ...

  10. getObjectURL 上传图片预览

    js 函数 function getObjectURL(file) {    var url = null ;     if (window.createObjectURL!=undefined) { ...