js 代码的运行机制

news2024/12/25 0:51:13

前言: 自己从一开始学习 javaScript 的时候,踩过很多很多坑,初学之路上也问过很多大佬许多为什么...现在回过头感叹,当时问的某些问题确实是有一丢丢幼稚。但是作为一个过来者,我深知这些问题的对于很多“后来者”来说,同样是非常宝贵的经验。所以全文会以“假如我是一个初学者,如果当初有人这样告诉我,那么我大概也能明白”。的角度去解释每一个细小的知识点,让你一步一步进阶。

作为一个淋过雨的人,想为后来者撑一把伞。


一. 什么是即时编译型语言

  1. 我相信每一个学习前端的都知道 JavaScript 是一门单线程解释型语言,或者更贴切的叫法为即时编译型语言。首先我们先不看单线程这个词。那么所谓的即时编译型语言这个名词到底是什么意思呢?

  2. 你可能没有深入了解过 java,go 这种编译型语言。js 和它们好像看起来就只差了两个字 ---“即时”。但是它们之间的行为差距是非常巨大的。别着急,我们一步一步理解。

  3. 我们首先看一下 script 这个单词的翻译。

这里我想引用单词 scripted 的翻译”照稿子念的“来进行接下来的讲解。我们先记住这个翻译。

  1. 我先问个问题:电影我们都很喜欢看🎬,对吧?那电影是需要“剧本”这个东西才可以进行的。剧本 包括了故事情节,每一个人的台词等非常重要的元素。

  2. 现在我们想象一个画面,一个已经完成的剧本摆在你面前。(就好比是一份需求文档)你需要用程序去把这个剧本里的画面去描绘出来。我来简单解释一下用即时编译型语言和编译型语言之间的差距。

  3. OK,我们先拿编译型语言GO” 来编写看看是什么样子的。首先我们需要把这个剧本整个读一遍。是的,没错,你需要从第一页到最后一页通读整个剧本,看看里面有没有错别字。然后如果有错别字,你就需要先修改完错别字再进行拍摄。并且尴尬的是拍摄完以后,发现某些镜头不满意,那么我们就需要先修改剧本,然后把这部电影从头开始再进行拍摄。

真实的过程:我们100行 go 代码全部从头到尾走一遍,然后编译成计算机所认识的二进制代码,也就是常见的.exe 可执行文件,最后计算机整体执行整个文件。

  1. 那现在我们如果使用即时编译型语言JS来编写会是什么情况呢?我们拿到剧本,看到第一页。emmm,剧情大概描述了“是一个大雪纷飞的场景”,ok,看到这你就可以直接拿起摄像机开始拍了,后面的剧情你不需要知道,没错,你可以看到哪里拍到哪里。从而引出上面我们提到的我们就是照稿子念的。看到哪念到哪里。如果有台词错误,我们可以随之马上修改,因为我们是边读边写的。(Chrome v8引擎在拿到剧本后所做的事情)

真实的过程:我们100行 js 代码,V8 读到第一行,就翻译第一行为 二进制代码,然后计算机帮我们运行。

  1. 聪明的你可能发现了,即时编译型语言 js 多了一个V8引擎翻译的环节。那么自然而然在执行速度上,就会略微逊色于编译型语言。

二. JS 设计为单线程的原因

  1. 我们先假设 JS 是多线程看看会造成什么后果。现在 JS 不再是从上到下一行一行执行了,那么它在执行的期间,难免就会遇到同一时间。某一个线程接收到信号,我需要修改 body 的背景颜色为红色。而另外一个线程接受到信号,需要把整个 body 的背景颜色修改为蓝色,那么我们到底听谁的?(注意你是多线程,必定会存在同一时间点两个线程做同一件事,所以这里我们不能按照哪个线程在后面就听谁的想法去思考)

  2. 所以 JS 是单线程的原因是因为它要干的事情决定的。并不是多线程可以充分利用 cpu 的高性能,我们就无脑选择多线程。

  3. 也正是 js 是单线程即时编译型语言的特点,我们在最开始学习 html 标签的时候,就会被老早的告知:“要把 <srcipt> 标签放在 body 后面。”

  1. 假设我们现在 <srcipt> 标签放在 <div> 标签前。那么假设我的 js 代码里存在 通过id 获取元素的这个方法。

document.getElementById("app")

那么就会造成,app 元素本身还没渲染出来,但是你就通过函数获取我。那么你肯定就只能拿到 undefined 了。

三. 单线程的后果

  1. 既然是 js 是单线程,那么我们就难免会遇到单线程难以解决的问题。假设我现在在进行一个很大的操作开销。

  2. 我们用 window.alert ,这个代码来“模拟”很大的开销的场景。(可能有些不太妥当)。我们都知道,这个方法会在用户加载页面的时候弹出一个对话框,来提醒某些事情。

上面是很简单的代码,我们看一下效果。

  1. 很明显可以看到,当我们进行“某些需要花时间”的操作的时候,由于我们的代码是从上而下执行的,势必就会造成我后面的代码需要花时间等你去执行完以后,我才可以去执行。

  2. 这种现象类比于到现实生活都是让人闹笑话的行为。我现在需要煮大米,我坐上电饭煲以后提示我30分钟后煮熟。那么在这三十分钟之内我什么其他事情都不能干了,我只能在电饭煲前面傻等着大米好了以后,我才能去买菜,炒菜。

  3. 所以既然 单线程 的本质我们无法更改,那么我们到底该如何解决这个问题呢?没错,JS 采用了事件循环(event loop) 的机制来解决这个办法。

四. 事件循环(event loop)

  1. 看过我上篇手把手教你实现防抖函数的同学大概会清楚一丢丢这个事情。在这里我再拓展讲解一下。

  2. 让我们再回到上面煮大米的现实案例。我现在被告知大米三十分钟以后做好,那么我在当下发现菜还没有买,我需要去买菜。我于是拿起手机定了个闹钟⏰,记下《30分钟以后,大米做好》这件事,然后我继续去买菜。当然做菜只能是在买菜之后才可以进行的事情,所以买菜和做菜之间的顺序还是不能打乱的。

  3. 那类比到我们的代码上。

我给做饭开启一个定时器,让他3秒后告诉我饭做好了,此时我的菜也买好炒好了。(我的页面也刷新好了,你随便怎么提醒我都不会影响我的页面了)

我们来试一下

  1. 可以很清楚的看到,我们的页面是先渲染出了样式,再弹出的提醒。这个“花费大时间的操作”并没有影响我们的使用体验。

  2. 这是我们的代码在执行时候的第一步。

编译器在执行到某一行的时候,会区分当前⬆是同步任务还是一步任务。如果是同步任务,那么推送到主线程上,如果是一步任务,那么推送到任务队列里去乖乖排队,你不能影响我的主线程。(类比上面就是 setTimeout 的回调函数window.alert被送到了任务队列里,而我们的 dom 加载被放到了主线程,第一时间执行。)

  1. 接下来主线程任务执行完毕后,就会去询问任务队列,看看有没有任务了。

有的话,就把它放进主线程去执行。没有的话,那我就隔一段时间问一下任务队列有没有,隔一段时间就问一次,无限重复下去。这就形成了“事件循环”(这是简易版,歧视背后还有很多操作,但是大致的概念是这样的)

结语

本原意我是直接想开始编写《手把手教你实现一个 Promise》的。但是我害怕有的读者不是特别清楚原理。如果上来就描述 Promise 里宏任务和微任务的概念的话,害怕有的新人读者读不下去,所以就打算慢慢来讲解。

《手把手带你实现 Promise》 同样会像《手把手教你实现 防抖函数》一样,会带你一步一步去构思这个过程。觉得文章写的还行的读者可以点个关注,防止以后找不到哦~

特别感谢

@风潋水漪

我们公司的后端大佬~对于《编译型语言和非编译型语言区别》环节提出的修改意见🎁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59063.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

tensorflow的模型持久化

参考 tensorflow的模型持久化 - 云社区 - 腾讯云 目录 1、持久化代码实现 2、持久化原理及数据格式 1、meta_info_def属性 2、graph_def属性 3、saver_def属性 4、collection_def属性 1、持久化代码实现 tensorflow提供了一个非常简单的API来保存和还原一个神经网络模型…

自主式模块化无人机设计

目 录 摘 要 I Abstract II 1 绪论 1 1.1 研究背景与意义 1 1.2 国内外研究现状 1 1.3 主要研究内容 2 2自主式模块化无人机的总体结构设计 3 2.1结构形式 3 2.2工作原理 3 2.3机架及桨叶的选择 5 2.3.1 单个桨叶空气动力分析及桨叶的选择 5 2.3.2材料的选择 6 2.3.3机架结构分…

【教学类-20-01】20221203《世界杯16强国旗》(大班)

展示效果&#xff1a; 单人使用样式&#xff1a; 多页打印样式 ​ 背景需求&#xff1a; 做《蒙德里安》格子画时&#xff0c;我把A4纸分割为正方形画框和长条纸支撑。活动中幼儿询问&#xff1a;为什么我的画站不起来&#xff1f;&#xff08;底边剪的不平整、提手太重、画…

知识直播:时代乐见搜狐的长期主义选择

国内著名商业咨询顾问刘润说&#xff1a;“所有伟大的机会都源自于巨大的结构性改变。大成就背后&#xff0c;一定有涌动的、因商业逻辑巨变而释放出来的红利。” 这话用在当前的互联网行业身上再好不过。面对重重不确定性&#xff0c;如何拨开迷雾&#xff0c;看懂市场趋势&a…

HTTP到底是什么?

文章目录HTTP简介HTTP协议的特点1) 简单快速2) 灵活3) 无连接4) 无状态HTTP协议的发展历程1) HTTP/0.92) HTTP/1.03) HTTP/1.14) HTTP/2.0HTTP的工作流程HTTP简介 HTTP 全称为 Hypertext Transfer Protocol&#xff0c;翻译为中文是“超文本传输协议”的意思&#xff0c;它是互…

Java并发编程—volatile

文章目录volatile的应用volatile的定义与实现原理专业术语&#xff1a;volatile是如何来保证可见性的呢&#xff1f;volatile的原理&#xff1a;volatile的两条实现原则&#xff1a;&#xff08;物理上如何实施&#xff09;volatile的内存语义volatile的特性例&#xff1a;下面…

SpringBoot -集成Druid

文章目录Druid概述使用问题解决Spring监控不生效方式1&#xff1a;修改yml的配置写法方式2&#xff1a;参考DruidSpringAopConfiguration自行注入Bean&#xff0c;灵活&#xff08;更建议&#xff09;Druid 概述 官网&#xff1a; https://github.com/alibaba/druid   文档&a…

校园论坛(Java)—— 用户管理系统模块

校园论坛&#xff08;Java&#xff09;—— 用户管理系统模块 文章目录校园论坛&#xff08;Java&#xff09;—— 用户管理系统模块[toc]1、写在前面2、系统结构设计2.1 各个页面之间的调用关系2.2. 用户管理系统模块各层的设计3、管理员管理用户功能3.1 管理员查看普通用户的…

微服务框架 SpringCloud微服务架构 10 使用Docker 10.1 镜像命令

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构10 使用Docker10.1 镜像命令10.1.1 镜像相关命令10.1.2 镜像操作命令10.1.…

SpringBoot_整合PageHelper

分页插件/PageHelper插件 我们在正常的查询业务之中,只需要加上一行代码就可以实现分页的数据的封装处理 实现原理 PageHelper方法使用了静态的ThreadLocal参数&#xff0c;分页参数和线程是绑定的。内部流程是ThreadLocal中设置了分页参数&#xff08;pageIndex&#xff0c…

TypeScript21(装饰器Decorator)

Decorator 装饰器是一项实验性特性&#xff0c;在未来的版本中可能会发生改变 不仅增加了代码的可读性&#xff0c;清晰地表达了意图&#xff0c;而且提供一种方便的手段&#xff0c;增加或修改类的功能&#xff1b; 若要启用实验性的装饰器特性&#xff0c;你必须在命令行或…

计算机网络 HTTPS

HTTPS HTTPS &#xff08;全称&#xff1a;Hypertext Transfer Protocol Secure &#xff09;&#xff0c;是以安全为目标的 HTTP 通道&#xff0c;在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 。HTTPS 在HTTP 的基础下加入SSL&#xff0c;HTTPS 的安全基础是…

git:多分支管理

多分支管理1. 列出分支2. 新建分支3. 删除分支4. 切换分支5. 分支合并多分支开发的特点 | 作用1. 测试&#xff1a;合并之后再在分支中工作是否主分支里面的相同文件不会更改2. 测试&#xff1a;修改编辑test分支的文件&#xff0c;最后再合并分支&#xff0c;是否是直接覆盖&a…

FT2004(D2000)开发实战之启动流程介绍

一 启动流程概述 飞腾FT2004/D2000芯片提供两种引导方案,具体如下所示: 方案一: 方案二: 方案一和方案二的区别是第二阶段的运行组件不同,方案一运行的是U-boot、方案二运行的是UEFI 那么为什么会这样的了? 答案是:飞腾FT2004/D2000芯片既可以用于嵌入式方案,也可以…

Docker中网络的使用和配置用法详解

一、单个物理机中docker网络 1.1 Docker默认网桥 安装Docker 服务默认会创建一个 docker0 网桥&#xff08;其上有一个 docker0 内部接口&#xff09;&#xff0c;它在内核层连通了其他的物理或虚拟网卡&#xff0c;这就将所有容器和本地主机都放到同一个物理网络。 使用 doc…

初识猿如意开发工具

嗨&#xff0c;大家好&#xff0c;我是异星球的小怪同志 一个想法有点乱七八糟的小怪 如果觉得对你有帮助&#xff0c;请支持一波。 希望未来可以一起学习交流。 一、初遇猿如意 第一次听说猿如意开发工具&#xff0c;于是抱着试试的心态&#xff0c;开始下载尝试。 首先是…

算法导论23章最小生成树习题—23.2练习

23.2-1对于同一个输人图&#xff0c;Kruskal 算法返回的最小生成树可以不同。这种不同来源于对边进行排序时&#xff0c;对权重相同的边进行的不同处理。证明:对于图G的每棵最小生成树T&#xff0c;都存在一种办法来对G的边进行排序&#xff0c;使得Kruskal算法所返回的最小生成…

HTML+CSS+JS网页设计期末课程大作业——上海旅游景点(10页)web前端开发技术 web课程设计 网页规划与设计

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

离散化【带题讲解】

全文目录&#x1f914; 原理&#x1f615; 区间和&#x1f635;‍&#x1f4ab; 建立映射&#x1f635;‍&#x1f4ab; 查找映射的下标&#x1f635;‍&#x1f4ab; 代码&#x1f914; 原理 离散化&#xff0c;把无限空间中有限的个体映射到有限的空间中去&#xff0c;以此提…

NVIDIA 安装 CUDA

名词解释&#xff1a;CUDA 是一个架构 该架构使GPU能够解决复杂的计算问题 此实战使用电脑为联想Y9000P 显卡型号为 3060 在安装 CUDA 之前需要先打开 NVIDIA 控制面板 一、准备工作 如图我这个显卡需要安装 CUDA 11.7 的版本 二、下载软件 进入官网下载 CUDA NVIDIA Deve…