客户端脚本语言:JS的运行机制
JavaScript一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标准通用标记语言下的一个应用)网页上使用,用来给HTML网页增加动态功能。
代码块: JS中的代码块是指由<script>标签分割的代码段。JS是按照代码块来进行编译和执行的,代码块间相互独立(即就算代码块1出错,但不影响代码块2的加载和执行),但变量和方法共享。
案例:2个代码块
<script type=\”text/javascript\”>
console.log(\”这是代码块一\”);
</script>
<script type=\”text/javascript\”>
console.log (\”这是代码块二\”);
</script>
HTML页面中JS的加载原理: 在加载HTML页面的时候,当浏览器遇到内嵌的JS代码时会停止处理页面,先执行JS代码,然后再继续解析和渲染页面。同样的情况也发生在外链的JS文件中,浏览器必须先花时间下载外链文件中的代码,然后解析并执行它,在这个过程中,页面的渲染和用户互交完全被阻塞。由于现代浏览器都允许并行下载JS文件,因此<script>标签在下载外部资源时不会阻塞其他的<script>标签。遗憾的是JS下载过程仍然会阻塞其他资源的下载。
JavaScript的单线程:
JS语言的一大特点就是单线程,也就是说,同一个时间只能做一件事情。之所以是单线程,是因为与它的用途有关,作为浏览器脚本语言,JS的主要用途是与用户互动以及操作DOM。这决定了它只能是单线程,否则会带来复杂的同步问题。为了利用多核CPU的计算功能,HTML5提出了web worker标准,允许JS脚本创建多个线程,但是子线程完全受主线程控制,且不能操作DOM,所以这个新标准并没有改变JS单线程的本质。
JavaScript的任务列队:
JS任务可以分为两种:一种是同步任务,另一种是异步任务。注意,只有主线程空了,才会去读取\”任务队列\”,这就是JS的运行机制,这个过程会不断重复。
同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕了,才会执行后一个任务。
异步任务:在主线程之外,还存在一个“任务列队”,异步任务就是不进入主线程,而是进入“任务列队”的任务,只有“任务列队”通知主线程,某个异步任务可以执行了并且同步任务执行完毕,该任务才会进入主线程执行。
Javascript的事件和回调函数:
\”任务列队\”是一个事件的列队,IO设备完成一项任务,就在\”任务队列\”中添加一个事件,表示相关的异步任务可以进入\”执行栈\”了。主线程读取\”任务队列\”,就是读取里面有哪些事件。\”任务队列\”中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(如鼠标点击、页面滚动等等)。只要指定过回调函数,这些事件发生时就会进入\”任务队列\”,等待主线程读取。
所谓\”回调函数\”,就是那些会被主线程挂起的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。\”任务队列\”是个先进先出的数据结构,排在前面的事件,优先被主线程读取。
主线程的读取过程基本上是自动的,只要执行栈一清空,\”任务队列\”上第一位的事件就自动进入主线程。但是,由于存在后文提到的\”定时器\”功能,主线程首先检查一下执行时间,某些事件只有到了规定的时间,才能返回主线程。
定时器:
除了放置异步任务的事件,\”任务队列\”还可以放置定时事件,即指定某些代码在多少时间之后执行。定时器功能主要由setTimeout和setInterval这两个函数来完成,它们的内部运行机制完全一样,区别在于前者指定的代码是一次性执行,后者则为反复执行。以下主要讨论setTimeou方法:
setTimeout接受两个参数,第一个是回调函数,第二个是推迟执行的毫秒数
console.log(1)
setTimeout(function {
console.log(2)
}, 1000);
console.log(3)
上面代码的执行结果是1=>3=>2,因为setTimeout将第二行推迟到1000毫秒之后执行
如果将setTimeout的第二个参数设为0,就表示当前代码执行完(执行栈清空)以后立即执行
setTimeout(function {
console.log(2)
}, 0);
console.log(3)
上面代码的执行结果是3=>2,因为只有在执行完第二行以后,系统才会去执行\”任务队列\”中的回调函数。总之,setTimeout(fn, 0)的含义是,指定某个任务在主线程最早的空闲时间执行,也就是说尽可能早的执行。它在\”任务队列\”的尾部添加一个事件,因此要等到同步任务和\”任务队列\”现有的事情都处理完,才会得到执行。
需要注意的是,setTimeout知识将事件插入了\”任务队列\”,必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数,要是当前代码耗时很长,有可能要等很久,所以并没有办法保证回调函数一定会在setTimeout指定的时间执行。
内容来源:博客园
编程语言背后的哲学:为什么选择JavaScript
JavaScript 是目前世界上最流行的编程语言之一,广泛应用于Web开发、服务器端开发、移动应用开发等多个领域。它的流行不仅仅是因为它能解决技术上的问题,更多的是因为它背后有一种强大的哲学思想,这种思想决定了它的灵活性、可扩展性和与现代开发需求的紧密契合。本文将深入探讨为什么选择 JavaScript,以及它背后的哲学理念。
JavaScript 的最大特点是它诞生于 Web,并与 Web 紧密结合。Web 是现代互联网的核心,JavaScript 正是为了满足 Web 页面交互性而设计的。
- Web 中的唯一脚本语言: JavaScript 是唯一一个被所有主流浏览器(如 Chrome、Firefox、Safari、Edge)支持的脚本语言,这使得它成为前端开发的标准语言。用户在浏览器中加载页面时,JavaScript 可以直接执行,从而在客户端实现动态交互。
- 全栈开发的基础: 随着 Node.js 的出现,JavaScript 不仅仅是前端开发语言,它逐渐成为服务器端编程的利器,使得开发者可以使用同一种语言进行全栈开发。这种跨越前端和后端的能力,使得 JavaScript 在开发领域中占据了极为重要的位置。
哲学背后: JavaScript 的设计理念强调与浏览器的高度集成,利用浏览器本身的强大能力进行高效的用户交互。它的设计哲学遵循“即开即用”,让开发者能够快速见到结果,并与用户产生互动。
JavaScript 具有很高的灵活性,这既是其优点,也是它有时被批评的地方。语言的松散性和宽容性使得开发者能够以多种方式编写代码,这对于快速开发和原型设计非常有利。
- 动态类型: JavaScript 是一种动态类型语言,意味着变量的数据类型不需要提前声明。开发者可以在运行时更改变量的类型,这让编程变得更加灵活。例如:
- let x = 5; x = \”Hello, world!\”; console.log(x); // 输出 \”Hello, world!\”
- 动态类型化降低了开发过程中的约束,能更快地进行原型开发,尤其适合快速迭代和变化频繁的项目。
- 宽容的错误处理: JavaScript 通常宽容于开发者犯一些小错误,如忘记分号,或者给变量赋值未定义的值。这个特性使得新手程序员能够更快速地开始编程,同时也让语言更加灵活。
哲学背后: JavaScript 的这种宽容性和灵活性反映了“以人为本”的设计理念,鼓励开发者快速试错、灵活调整,适应多变的需求。它降低了技术门槛,让更多的人能够参与进来。
JavaScript 从一开始就设计为支持事件驱动和异步编程。这种设计哲学使得 JavaScript 在处理 I/O 操作(如网络请求、文件读写)时非常高效,避免了阻塞和同步编程中可能遇到的性能瓶颈。
- 事件循环(Event Loop): JavaScript 在浏览器和 Node.js 中都基于事件循环机制,能够处理高并发和大量异步任务。通过这种机制,JavaScript 能够在执行其他代码时并行处理事件、回调和异步任务,不会被阻塞。
- Promise 和 async/await: JavaScript 引入了 Promise 和 async/await 语法,使得异步代码更加清晰和易于理解。开发者可以像写同步代码一样处理异步逻辑,大大提升了代码的可维护性和可读性。
哲学背后: 事件驱动和异步编程的设计理念源自“非阻塞”思想,它让 JavaScript 能够处理高并发任务,而不牺牲性能。这一理念特别适合现代网络应用,尤其是实时通信、数据流和高度交互的 Web 应用。
JavaScript 是一种多范式语言,既支持面向对象编程(OOP),也支持函数式编程(FP)。这使得开发者可以根据实际需求选择最适合的编程方式。
- 面向对象: JavaScript 从 ES6 开始引入了类(class)这一语法糖,使得它支持传统的面向对象编程。开发者可以使用类和继承等机制组织代码,创建可复用和可扩展的组件。
- 函数式编程: JavaScript 也具备高阶函数、闭包、函数作为一等公民等函数式编程的特性。开发者可以使用纯函数、map、filter 等方法来编写简洁且可组合的代码。函数式编程让代码更具表达性,避免了副作用,提高了可测试性。
哲学背后: JavaScript 支持多种编程范式的设计哲学体现了灵活性和包容性。它鼓励开发者根据不同问题的需要,选择最适合的编程方式。这种灵活性使得 JavaScript 可以适应各种开发需求,成为全栈开发的首选语言。
JavaScript 的强大还在于其庞大的社区支持和丰富的生态系统。语言本身的设计允许第三方库和框架快速诞生,这使得 JavaScript 的功能不断扩展。
- 庞大的生态系统: 从 React、Vue 到 Angular,再到 Node.js、Express、Nest.js 等后端框架,JavaScript 的生态系统涵盖了从前端到后端、从数据库到 API 的所有层次。这些框架和工具使得开发者可以专注于应用的业务逻辑,而不需要从零开始构建所有的功能。
- NPM(Node Package Manager): JavaScript 的包管理工具 NPM 是世界上最大的开源包管理系统之一。开发者可以通过 NPM 轻松安装、管理和共享库和模块,这极大提高了开发效率。
哲学背后: JavaScript 的开源和社区驱动的设计哲学使得它具有强大的适应性和持续创新的能力。社区的活跃和开源项目的不断发展让 JavaScript 迅速适应新的需求,保持竞争力。
JavaScript 不仅在浏览器中流行,还被广泛应用于其他平台,如桌面应用、移动应用、物联网等。
- 跨平台开发: 利用像 React Native 这样的框架,JavaScript 也可以用于开发原生的移动应用。通过 Electron,开发者可以使用 JavaScript 构建跨平台的桌面应用。
- 物联网(IoT)和嵌入式设备: JavaScript 也可以用于物联网设备的编程。例如,Node.js 被用于 Raspberry Pi 等嵌入式设备的开发,这展示了 JavaScript 在不同平台上的广泛适应性。
哲学背后: JavaScript 的跨平台特性体现了“无处不在”的设计思想。它能够运行在多种设备和平台上,这使得开发者可以用同一套代码实现不同终端的应用,极大提高了开发效率和应用的普适性。
JavaScript 的哲学源自其对灵活性、可扩展性和与用户互动的高度重视。它的设计理念使得它能够在多种开发环境中高效运作,无论是前端、后端,还是跨平台应用。JavaScript 的宽容性、事件驱动、异步编程、多范式支持以及庞大的社区生态系统,构成了其成功的核心。
选择 JavaScript,不仅是选择了一种编程语言,更是选择了一种开发哲学——灵活、快速、高效且与时俱进。无论是初学者还是资深开发者,JavaScript 都为你提供了一个广阔的舞台来实现创意和功能,面对不断变化的技术需求,JavaScript 依然保持着它的核心竞争力。
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。