昆明医院网站建设/灰色词网站seo

昆明医院网站建设,灰色词网站seo,wordpress大主题上传,济南高端网站一、预解析是什么? 在前端开发中,我们常常会遇到一些看似不符合常规逻辑的代码执行现象,比如为什么在变量声明之前访问它,得到的结果是undefined,而不是报错?为什么函数在声明之前就可以被调用&#xff1f…

一、预解析是什么?

在前端开发中,我们常常会遇到一些看似不符合常规逻辑的代码执行现象,比如为什么在变量声明之前访问它,得到的结果是undefined,而不是报错?为什么函数在声明之前就可以被调用?这些问题的答案,都与前端的预解析机制有关。那预解析究竟是什么呢?

简单来说,预解析是 JavaScript 解析器在运行代码前的一个重要处理步骤。当 JavaScript 代码被加载到浏览器中时,解析器并不会立即逐行执行代码,而是会先进行预解析。在这个阶段,解析器会将所有带有var声明的变量和function声明的函数,在内存中进行提前声明或者定义。 这样做的目的是为了让 JavaScript 引擎在正式执行代码时,能够更高效地处理变量和函数的调用,避免因为变量或函数未定义而导致的错误。

二、预解析的类型

(一)全局预解析

当我们在浏览器中打开一个包含 JavaScript 代码的页面时,全局预解析就开始了。它会对全局代码进行通读,找出所有使用var声明的变量和function声明的函数。在这个过程中,变量只是被声明,并不会被赋值,而函数则会被完整地定义。需要注意的是,函数体内的代码在全局预解析阶段不会被处理 。

例如以下代码:

console.log(num);var num = 10;function fn() {console.log('这是一个函数');}fn();

在全局预解析阶段,浏览器会先找到var num,将num声明为一个变量,但此时num的值为undefined。接着找到function fn,将fn定义为一个函数。当真正开始执行代码时,console.log(num)会输出undefined,因为此时num虽然已经声明,但还未被赋值。然后执行num = 10,给num赋值为 10。最后调用fn函数,输出 “这是一个函数”。

(二)局部预解析

局部预解析发生在函数被调用的时候。当一个函数被调用时,会创建一个私有作用域,在这个私有作用域内,会对函数内部的代码进行预解析。同样,它会查找函数内使用var声明的变量和function声明的函数,变量声明会被提前,函数也会被提前定义,解析完成后才会执行函数体里的代码。

以下面这段代码为例:

function test() {console.log(a);var a = 5;console.log(a);function inner() {console.log('这是内部函数');}inner();}test();

在调用test函数时,进入局部预解析阶段。首先,在这个私有作用域内找到var a,将a声明为局部变量,值为undefined,同时找到function inner,将inner定义为一个函数。然后开始执行函数体代码,console.log(a)会输出undefined,接着执行a = 5,给a赋值为 5,再次执行console.log(a),输出 5。最后调用inner函数,输出 “这是内部函数”。

三、预解析解析的内容

(一)var 声明

在 JavaScript 中,使用var声明变量时,会发生变量提升现象,即变量的声明会被提升到其所在作用域的顶部,但变量的赋值操作并不会被提升,仍然保留在原来的位置。这意味着,我们可以在变量声明之前访问它,只不过此时它的值是undefined。

例如:

console.log(num);var num = 10;console.log(num);

在上述代码中,第一行console.log(num)输出的结果是undefined。这是因为在预解析阶段,var num被提升到了当前作用域的顶部,相当于代码变成了:

var num;console.log(num);num = 10;console.log(num);

所以,在第一个console.log(num)执行时,num已经被声明,但还没有被赋值,其值为undefined。而在执行num = 10后,第二个console.log(num)输出的结果就是 10。

(二)函数声明

函数声明在预解析阶段也会被提升,与变量提升不同的是,函数声明是整个函数定义被提升,而不仅仅是函数名。这就使得我们可以在函数声明之前调用它。

例如声明式函数:

fn();function fn() {console.log('这是一个声明式函数');}

在这个例子中,fn()函数调用在函数声明之前,但代码依然能够正常执行,输出 “这是一个声明式函数”。这是因为在预解析阶段,函数fn的定义被提升到了作用域的顶部,所以在调用时,JavaScript 引擎已经知道了fn是一个函数。

再看赋值式函数:

fn2();var fn2 = function() {console.log('这是一个赋值式函数');};

上述代码中,fn2()函数调用会报错,提示fn2 is not a function。这是因为在预解析阶段,只有var fn2被提升,此时fn2只是一个普通变量,值为undefined,还没有被赋值为函数。当执行到fn2()时,fn2还不是一个函数,所以会报错 。只有在执行到var fn2 = function() {... }时,fn2才被赋值为一个函数。

四、预解析原理揭秘

了解了预解析的类型和内容后,我们来深入探究一下预解析的原理。在浏览器中,预解析是与 HTML 解析并行进行的一个重要过程 。当浏览器接收到 HTML 文档后,会开启一个主线程来解析 HTML,同时启动一个预解析线程。预解析线程的主要任务是扫描 HTML 文档,寻找其中的外部资源引用,如<link>标签引用的 CSS 文件、<script>标签引用的 JavaScript 文件以及<img>标签引用的图片等,并提前下载这些资源。

在解析 HTML 时,假设遇到了如下代码:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><link rel="stylesheet" href="styles.css"><script src="script.js"></script></head><body><img src="image.jpg" alt="示例图片"></body></html>

主线程在解析到<link rel="stylesheet" href="styles.css">时,会继续解析后续的 HTML 内容,而预解析线程则会立即开始下载styles.css文件。同样,当解析到<script src="script.js"></script>时,预解析线程也会下载script.js,以及解析到<img src="image.jpg" alt="示例图片">时,下载image.jpg。这样,当主线程后续需要这些资源时,它们可能已经被下载完成,从而减少了等待时间,提高了页面的加载速度和渲染效率。

需要注意的是,对于<script>标签,如果没有使用async或defer属性,浏览器会按照默认行为暂停 HTML 解析,并等待脚本下载和执行完毕。因为 JavaScript 代码的执行可能会修改 DOM 树结构,所以为了保证 DOM 树的一致性,在执行 JavaScript 时,HTML 解析会被暂停。但在预解析阶段,预解析线程可以提前开始下载这些脚本文件,即使尚未到达需要执行它们的部分。

五、预解析常见问题及解决

(一)变量提升与作用域

在 JavaScript 中,变量提升和作用域的概念紧密相关,这也导致了一些容易让人困惑的问题。

  • 局部变量遮蔽全局变量:当局部作用域中声明了与全局变量同名的变量时,就会发生局部变量遮蔽全局变量的情况。在局部作用域内,对该变量的访问和操作都将针对局部变量,而不会影响到全局变量。

例如:

var num = 10;function test() {var num = 20;console.log(num);}test();console.log(num);

在上述代码中,全局作用域中声明了变量num并赋值为 10。在test函数内部,又声明了一个同名的局部变量num并赋值为 20。在test函数内,console.log(num)输出的是局部变量num的值 20,因为局部变量遮蔽了全局变量。而在函数外部,console.log(num)输出的依然是全局变量num的值 10 。

  • 函数参数与变量提升:当函数参数与函数内部使用var声明的变量同名时,会出现一些特殊的情况。函数参数会被优先提升,并且函数内部的var声明会被忽略,但赋值操作仍然会执行。

例如:

function fun(param) {console.log(param);var param = function () {console.log(1);};console.log(param);}fun(5);

在这个例子中,调用fun(5)时,参数param被赋值为 5。在函数内部,虽然有var param的声明,但由于参数param已经存在,这个声明会被忽略。所以,第一个console.log(param)输出的是参数param的值 5。接着,param被赋值为一个函数,此时第二个console.log(param)输出的就是这个函数 。

为了避免这些问题,我们在编写代码时,应该遵循一些最佳实践:

  • 尽量避免在不同作用域中使用相同的变量名,以减少变量遮蔽带来的困惑。
  • 养成良好的变量命名习惯,使变量名具有描述性,能够清晰地表达其用途。
  • 在函数内部,明确区分函数参数和局部变量,避免同名冲突。

(二)函数声明与变量声明的优先级

在 JavaScript 中,函数声明和变量声明都存在提升现象,但函数声明的优先级高于变量声明。这意味着在预解析阶段,函数声明会先被提升到作用域的顶部,然后才是变量声明。

当函数声明和变量声明同名时,函数声明会覆盖变量声明,但变量的赋值操作会在执行阶段覆盖函数的定义。例如:

console.log(foo);function foo() {console.log('这是一个函数');}var foo = 10;console.log(foo);

在上述代码中,第一个console.log(foo)输出的是函数foo的定义。这是因为在预解析阶段,函数声明function foo()被提升到了作用域的顶部,此时foo是一个函数。接着,var foo的声明也被提升,但它不会覆盖已经存在的函数声明。在执行阶段,foo = 10将foo赋值为 10,所以第二个console.log(foo)输出的是 10 。

再看下面这个例子:

function bar() {console.log(a);var a = 5;function a() {console.log('这是内部函数');}console.log(a);}bar();

在bar函数中,预解析时,函数声明function a()先被提升,然后是var a的声明(这个声明会被忽略,因为已经有同名的函数声明)。所以第一个console.log(a)输出的是函数a。接着,执行a = 5,将a赋值为 5,此时第二个console.log(a)输出的就是 5。如果此时再调用a(),就会报错,因为a已经被赋值为 5,不再是一个函数 。

理解函数声明和变量声明的优先级,有助于我们写出更准确、可维护的代码。在实际开发中,要避免函数声明和变量声明同名,以免造成不必要的错误和困惑。

六、预解析对前端性能的影响

预解析在前端性能优化方面发挥着重要作用,尤其是在网络资源加载和页面渲染速度上。

(一)缩短 DNS 解析时间

DNS 解析是将域名转换为 IP 地址的过程,这个过程通常会消耗一定的时间,而 DNS 预解析(dns-prefetch)技术可以提前解析之后可能会用到的域名,使解析结果缓存到系统缓存中,从而缩短 DNS 解析时间。当浏览器解析 HTML 文档时,会遇到各种资源的引用,如<script>标签引用的 JavaScript 文件、<link>标签引用的 CSS 文件以及<img>标签引用的图片等,这些资源可能来自不同的域名,每次访问不同域名都需要进行 DNS 解析。例如,在一个电商网站的页面中,不仅有来自主域名的商品信息展示,还引用了第三方 CDN 上的图片资源和字体文件,以及其他合作平台的广告脚本,这些不同来源的资源都需要进行 DNS 解析。通过 DNS 预解析,浏览器可以在后台提前完成这些域名的解析工作,当真正需要加载这些资源时,就可以直接使用已经解析好的 IP 地址,减少了等待 DNS 解析的时间。

(二)提高页面加载速度

通过提前解析域名,浏览器能够更快地建立与服务器的连接,从而加快资源的下载速度。在一个复杂的前端应用中,可能会有大量的 JavaScript、CSS 和图片等资源需要加载。以一个在线新闻网站为例,页面上除了文章内容,还包含各种配图、广告、推荐文章链接等,这些资源分布在不同的域名下。如果没有预解析,浏览器在加载这些资源时,需要逐个进行 DNS 解析,这会导致页面加载时间延长。而使用预解析后,在页面解析的同时,DNS 解析已经在后台完成,资源可以更快地被下载和加载,大大提高了页面的加载速度,用户能够更快地看到完整的页面内容,提升了用户体验。

(三)减少资源加载阻塞

在浏览器解析 HTML 文档时,如果遇到<script>标签,会暂停 HTML 解析,先去加载和执行 JavaScript 代码,这是因为 JavaScript 代码可能会修改 DOM 树结构,为了保证 DOM 树的一致性,需要先执行 JavaScript。而在加载 JavaScript 文件时,又会涉及到 DNS 解析、建立连接、下载文件等过程,如果 DNS 解析时间过长,就会阻塞页面的渲染。预解析可以提前完成 DNS 解析,减少了这一过程对页面渲染的阻塞。例如,在一个视频播放网站中,视频播放器的初始化脚本可能需要从不同的域名获取配置信息和资源,通过预解析,这些域名的解析工作可以提前完成,当解析到<script>标签时,能够更快地加载和执行脚本,减少了视频播放前的等待时间,让用户能够更流畅地观看视频,避免了因资源加载阻塞而导致的页面卡顿或白屏现象。

七、最后小结

前端预解析作为 JavaScript 解析过程中的重要环节,对代码的执行顺序和结果有着深远的影响。它通过提前声明变量和函数,为代码的顺利执行奠定了基础。同时,DNS 预解析等技术的应用,也在前端性能优化方面发挥着关键作用,显著提升了页面的加载速度和用户体验。

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

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

相关文章

基于聚类与相关性分析对马来西亚房价数据进行分析

碎碎念&#xff1a;由于最近太忙了&#xff0c;更新的比较慢&#xff0c;提前祝大家新春快乐&#xff0c;万事如意&#xff01;本数据集的下载地址&#xff0c;读者可以自行下载。 1.项目背景 本项目旨在对马来西亚房地产市场进行初步的数据分析&#xff0c;探索各州的房产市…

范冰冰担任第75届柏林电影节主竞赛单元评委 共鉴电影佳作

近日&#xff0c;备受瞩目的柏林电影节迎来了新一届盛事&#xff0c;而华人演员范冰冰将以主竞赛单元评委身份亮相&#xff0c;引发了广泛关注。此前她已担任过戛纳国际电影节、东京国际电影节、圣塞巴斯蒂安国际电影节等众多电影节主竞赛单元评委。作为国际影坛的知名人物&…

Ollama 运行从 ModelScope 下载的 GGUF 格式的模型

本文系统环境 Windows 10 Ollama 0.5.7 Ollama 是什么&#xff1f; Ollama 可以让你快速集成和部署本地 AI 模型。它支持各种不同的 AI 模型&#xff0c;并允许用户通过简单的 API 进行调用 Ollama 的安装 Ollama 官网 有其下载及安装方法&#xff0c;非常简便 但如果希…

“腾讯、钉钉、飞书” 会议开源平替,免费功能强大

在数字化时代&#xff0c;远程办公和线上协作越来越火。然而&#xff0c;市面上的视频会议工具要么贵得离谱&#xff0c;要么功能受限&#xff0c;甚至还有些在数据安全和隐私保护上让人不放心。 今天开源君给大家安利一个超棒的开源项目 - Jitsi Meet&#xff0c;这可是我在网…

【教学类-89-01】20250127新年篇01—— 蛇年红包(WORD模版)

祈愿在2025蛇年里&#xff0c; 伟大的祖国风调雨顺、国泰民安、每个人齐心协力&#xff0c;共同经历这百年未有之大变局时代&#xff08;国际政治、AI技术……&#xff09; 祝福亲友同事孩子们平安健康&#xff08;安全、安全、安全&#xff09;、巳巳如意&#xff01; 背景需…

2025年1月30日(任意截面、自定义截面梁的设置)

Ansys 在ANSYS中&#xff0c;以下是这些术语的详细解释&#xff1a; Nodal Solution (节点解): Nodal Solution指的是在有限元分析中计算出的节点处的物理量解。通常包括节点的位移、反应力等信息。节点解是分析结果的基础&#xff0c;因为它们可以用来计算其他重要的物理量&a…

unity使用内置videoplayer打包到安卓手机进行视频播放

1.新建UI&#xff0c;新建RawImage在画布当作视频播放的显示载体 2.新建VideoPlayer 3.新建Render Texture作为连接播放器视频显示和幕布的渲染纹理 将Render Texture同时挂载在VideoPlayer播放器和RawImage上。这样就可以将显示的视频内容在RawImage上显示出来了。 问题在于&a…

【Envi遥感图像处理】008:波段(批量)分离与波段合成

文章目录 一、波段分离提取1. 提取单个波段2. 批量提取单个波段二、波段合成相关阅读:【ArcGIS微课1000例】0058:波段合成(CompositeBands)工具的使用 一、波段分离提取 1. 提取单个波段

MongoDB平替数据库对比

背景 项目一直是与实时在线监测相关&#xff0c;特点数据量大&#xff0c;读写操作大&#xff0c;所以选用的是MongoDB。但按趋势来讲&#xff0c;需要有一款国产数据库可替代&#xff0c;实现信创要求。选型对比如下 1. IoTDB 这款是由清华大学主导的开源时序数据库&#x…

C语言------数组从入门到精通

1.一维数组 目标:通过思维导图了解学习一维数组的核心知识点: 1.1定义 使用 类型名 数组名[数组长度]; 定义数组。 // 示例&#xff1a; int arr[5]; 1.2一维数组初始化 数组的初始化可以分为静态初始化和动态初始化两种方式。 它们的主要区别在于初始化的时机和内存分配的方…

物联网智能项目之——智能家居项目的实现!

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于物联网智能项目之——智能家居项目…

Nxopen 直齿轮参数化设计

NXUG1953 Visualstudio 2019 参考论文&#xff1a; A Method for Determining the AGMA Tooth Form Factor from Equations for the Generated Tooth Root Fillet //FullGear// Mandatory UF Includes #include <uf.h> #include <uf_object_types.h>// Internal I…

蓝桥杯模拟算法:蛇形方阵

P5731 【深基5.习6】蛇形方阵 - 洛谷 | 计算机科学教育新生态 我们只要定义两个方向向量数组&#xff0c;这种问题就可以迎刃而解了 比如我们是4的话&#xff0c;我们从左向右开始存&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;4 到5的时候y就大于4了就是越界了&…

VLLM性能调优

1. 抢占 显存不够的时候&#xff0c;某些request会被抢占。其KV cache被清除&#xff0c;腾退给其他request&#xff0c;下次调度到它&#xff0c;重新计算KV cache。 报这条消息&#xff0c;说明已被抢占&#xff1a; WARNING 05-09 00:49:33 scheduler.py:1057 Sequence gr…

HTML特殊符号的使用示例

目录 一、基本特殊符号的使用 1、空格符号&#xff1a; 2、小于号 和 大于号&#xff1a; 3、引号&#xff1a; 二、版权、注册商标符号的使用 1、版权符号&#xff1a;© 2、注册商标符号&#xff1a; 三、数学符号的使用 四、箭头符号的使用 五、货币符号的使用…

three.js用粒子使用canvas生成的中文字符位图材质

three.js用粒子使用canvas生成中文字符材质 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Three.…

STM32 PWM驱动直流电机

接线图&#xff1a; 代码配置&#xff1a; 根据驱动舵机的代码来写&#xff0c;与舵机不同的是&#xff0c;这次的引脚接到了PA2上&#xff0c;所以需要改一下引脚以及改为OC3通道。 另外还需在配置两个GPIO引脚&#xff0c;来控制电机的旋转方向&#xff0c;这里连接到了PA4与…

【外文原版书阅读】《机器学习前置知识》2.用看电影推荐的例子带你深入了解向量点积在机器学习的作用

目录 3.3 Where Are You Looking, Vector? The Dot Product 个人主页&#xff1a;Icomi 大家好&#xff0c;我是Icomi&#xff0c;本专栏是我阅读外文原版书《Before Machine Learning》对于文章中我认为能够增进线性代数与机器学习之间的理解的内容的一个输出&#xff0c;希望…

Conditional DETR for Fast Training Convergence论文学习

1. 写作背景 最近提出的 DETR 成功地将 transformer 引入到物体检测任务中&#xff0c;获得了很不错的性能。DETR 的重要意义在于去除了物体检测算法里需要人工设计的部分&#xff0c;比如 anchor 的生成和 NMS 操作。这大大简化了物体检测的设计流程。基本的结构还是沿用了以…

低代码产品表单渲染架构

在React和Vue没有流行起来的时候&#xff0c;低代码产品的表单渲染设计通常会使用操作Dom的方式实现。 下面是一个表单的例子&#xff1a; 产品层 用户通过打开表单&#xff0c;使用不同业务场景业务下的表单页面&#xff0c;中间的Render层就是技术实现。 每一个不同业务的表单…