JS核心知识点梳理——异步,单线程,运行机制

2019-05-26 admin

clipboard.png

引言

学习javascipt的时候,经常听人说,javascipt即是异步的,又是单线程的。究竟什么是异步,什么是单线程?javascript在浏览器中的运行机制是怎么样的?什么是eventloop,task queue?怎么写异步函数?相信读完这篇文章,相信你会对上面问题有一个全面的认识。

全面了解浏览器

浏览器有许多进程:

  1. Browser进程:浏览器的主进程(负责协调、主控),只有一个。
  2. 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
  3. GPU进程:最多一个,用于3D绘制等
  4. 浏览器渲染进程(浏览器内核)(Renderer进程,内部是多线程的)

在浏览器渲染进程中有许多线程:

  • 渲染引擎线程:顾名思义,该线程负责页面的渲染
  • JS引擎线程:负责JS的解析和执行(主线程)
  • 定时触发器线程:处理定时事件,比如setTimeout, setInterval
  • 事件触发线程:处理DOM事件
  • 异步http请求线程:处理http请求

虽然JavaScript是单线程的(说的是JS引擎线程),可是浏览器内部不是单线程的。一些I/O操作、定时器的计时和事件监听(click, keydown...)等都是由浏览器提供的其他线程来完成的。 主线程和渲染引擎线程互斥,因为渲染的时候主线程可能通过dom操作渲染结果,所以主线程必须被阻塞

单线程,异步

判断标准

之前傻傻的分不清楚单线程多线程,同步异步。其实很简单

异步的判断标准:是否阻塞,同步阻塞,异步不阻塞。

单线程的判断标准:一次是否只做一件事。

JS引擎一次只做一件事。遇到异步任务并不会阻塞后面的同步任务(不等待)。所以我们说JS是异步 单线程的。需要注意的是JS引擎其实并不提供异步的支持,异步支持主要依赖于运行环境(浏览器或Node.js)。

while阻塞实验

var start = new Date();
    while(new Date() - start < 100000) { // delay 10 sec
        ;
    }

上面代码在chrome控制台输入可以手动阻塞当前页面的js主线程10s。然后我们在当前页面输入console.log(1),当前页面无反应,在另外的页面输入console.log(1)直接打印 说明浏览器每个页面都会单独起一个进程,页面1的主线程被阻塞并不会影响影响页面2的主线程

执行机制

clipboard.png

JS Engine和runtime Environment

之前在Stackoverflow看了一个答案,感觉还比较靠谱

JavaScript Engine:parse your code and convert it to runnable commands JavaScript Runtime Environment :provide some objects to javascript so that it can interact with the outside world. For example, the Chrome Browser and node.js use the same Engine - V8, but their Runtimes are different: in Chrome you have the window, DOM objects etc, while node gives you require, Buffers and processes.

通俗的讲,上面这张图,左边你可以看成JS引擎,右边你可以看成JS运行环境

Eventloop

之前已经说了,JS在设计之初选择单线程,是以为单线程简单,可控。

但是单线程存在一个问题,部分任务比如Ajax请求数据,如果设计成同步的,后面的任务将都去等待Ajax请求完,这个性能是不能接受的。

所以浏览器内核(?个人推测,暂时没有找到相关资料)将任务分为同步任务和异步任务,所有同步任务放到主线程上执行,形成一个执行栈(execution context stack)。所以异步任务放到其他异步线程上去执行。

当异步任务执行完以后,相关回调函数会放入到消息队列(也有叫callback queue、task queue)中。

主线程同步任务执行完,每个一段事件会检查消息队列一次,有回调函数就会执行,如此往复就成为Eventloop

个人的理解 :JS引擎是同步的,浏览器通过eventloop这种机制实现了异步

看一下How JavaScript works 怎么描述这个过程的

So, for example, when your JavaScript program makes an Ajax request to fetch some data from the server, you set up the “response” code in a function (the “callback”), and the JS Engine tells the hosting environment: “Hey, I’m going to suspend execution for now, but whenever you finish with that network request, and you have some data, please call this function back.”

The browser is then set up to listen for the response from the network, and when it has something to return to you, it will schedule the callback function to be executed by inserting it into the event loop.

宏任务,微任务、练习

面试喜欢考宏任务(macrotask),微任务(microtask)。那么我们就来讲一讲macrotask和microtask是个啥子

宏任务又成为task。可以理解是每次执行栈执行的代码就是一个task,task1->渲染->task1

microtask,可以理解是在当前 task 执行结束后立即执行的任务,所以microtask有归属性,只在对应的task执行完后立即执行.task1->microtask1->渲染->task2->microtask2->渲染…

macrotask:主代码块,setTimeout,setInterval等(可以看到,事件队列中的每一个事件都是一个macrotask)

microtask:Promise,process.nextTick等

求下面代码的结果

console.log('1');
setTimeout(function() { //回调2
    new Promise(function(resolve) {
        console.log('2');
        resolve();
    }).then(function() {
        console.log('3')
    })
    console.log('4');
},2000)
new Promise(function(resolve) {
    console.log('5');
    resolve();
}).then(function() {
    console.log('6')
})

setTimeout(function() {  //回调1
    new Promise(function(resolve) {
        console.log('7');
        resolve();
    }).then(function() {
        console.log('8')
    })
      setTimeout(function(){ //回调3
        console.log('9')
    },2000)
},1000)

//(156) (78) (243) (9)

解析: task1: 输出1 5 ----> microtask1 输出6 --(执行栈空)–>render---->eventloop 1秒以后 callback queue里面加入回调1 被eventloop捕获,同步任务入栈,异步任务给settiomeout线程(也就是回调3的那个异步任务) task2: 输出7 ----> microtask2 输出8 --(执行栈空)–>render---->eventloop 2秒以后 callback queue里面加入回调2 被eventloop捕获,同步任务入栈 task3: 输出2 4 ----> microtask3 输出3 --(执行栈空)–>render---->eventloop 3秒以后 callback queue里面加入回调3 被eventloop捕获,同步任务入栈 task4: 输出9 --(执行栈空)–>render---->eventloop…

异步编程

回调函数实现

let fs = require('fs');
fs.readFile('./1.js','utf-8',(err,data)=>{
    //
    fs.readFile('./2.js','utf-8',(err,data)=>{
         //
         fs.readFile('./3.js','utf-8',(err,data)=>{
                //
         })
    })
})

缺点是容易形成回调地狱,不能return

promise

const fs = require('fs');
const readFile(i) = new Promise(function(){
     fs.readFile(`./${i}.js`,'utf-8',(err,data)=>{
            resolve(data)
         })
})
    readFile(1)
   .then(readFile(2))
   .then(readFile(3))
   .....

async await

async function read(){
 //await后面必须跟一个promise,
 let a = await readFile('./1.txt');
 console.log(a);
 let b = await readFile('./2.txt');
 console.log(b);
 let c = await readFile('./3.txt');
 console.log(c);
 return 'end';
 }

尾声

以上是我看了多篇文章以后,结合自己的理解,对javascript异步单线程,以及运行机制做的一个总结。如果你感觉哪一部分有点问题,欢迎在评论区留言。

参考

从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理 JavaScript 运行机制详解:再谈Event Loop JavaScript异步机制详解 JavaScript 运行原理解析 What is the difference between JavaScript Engine and JavaScript Runtime Environment 并发模型与事件循环

[转载]原文链接:https://segmentfault.com/a/1190000019297903

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-65768.html

文章标题:JS核心知识点梳理——异步,单线程,运行机制

相关文章
React.js编程思想
JavaScript框架层出不穷,在很多程序员看来,React.js是创建大型、快速的Web应用的最好方式。这一款由Facebook出品的JS框架,无论是在Facebook还是在Instagram中,它的表现都非常出色。 使用React.j...
2015-11-12
jsdom 中文文档(纯翻译)
jsdom是一个纯粹由 javascript 实现的一系列 web标准,特别是 WHATWG 组织制定的DOM和 HTML 标准,用于在 nodejs 中使用。大体上来说,该项目的目标是模拟足够的Web浏览器子集,以便用于测试和挖掘真实世界...
2018-05-14
从2014年的发展来展望JS的未来将会如何
&lt;font face=&quot;寰�杞�闆呴粦, Arial, sans-serif &quot;&gt;2014骞达紝杞�浠惰�屼笟鍙戝睍杩呴€燂紝鍚勭�嶈��瑷€灞傚嚭涓嶇┓锛屼互婊¤冻鐢ㄦ埛涓嶆柇鍙樺寲鐨勯渶姹傘€傝繖浜涜��...
2015-11-12
three.js实现围绕某物体旋转
话不多说,请看代码: 可以拖动右上角观察变化 &lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot; style=&quot;width: 100%; height:100%;&quot;&gt...
2017-02-17
JavaScript教程:JS中的原型
Keith Peters 几年前发表的一篇博文,关于学习没有“new”的世界,其中解释了使用原型继承代替构造函数。两者都是纯粹的原型编码。 标准方法(The Standard Way) 一直以来,我们学习的在 JavaScript 里创建对...
2015-11-12
JS中的语音合成——Speech Synthesis API
JS中的语音合成——Speech Synthesis API 简介 HTML5中和Web Speech相关的API实际上有两类,一类是“语音识别(Speech Recognition)”,另外一个就是“语音合成(Speech Synthes...
2018-05-17
NodeJS参考手册pdf版
下载地址:Nodejs参考手册PDF版下载 ...
2015-11-12
Node.js学习(1)----HTTP服务器与客户端
Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端。http.Server 是一个基于事件的 HTTP 服务器,它的核心由 Node.js 下层 C++部分实现,而接口由 Jav...
2015-11-12
使用jspdf生成pdf报表
由于前台html已经动态生成报表,而且,前台有一个功能,一个date range组件,当你拖动的时候,报表会在不提交到后台的情况下动态变化。 因此需要用到js生成生报表: 用到的组件: jquery.js jspdf.js canvg.js...
2017-03-25
Riot.js:不足1KB的MVP客户端框架
Riot.js是一款MVP(模型-视图-呈现)开源客户端框架,其最大的特点就是体积非常小,不足1KB,虽然体积小,但它可以帮助用户构建大规模的Web应用程序。 Riot.js是由Moot公司开发,目前最新版本为v0.9.2,遵循MIT开源许...
2016-03-11
回到顶部