JavaScript 到底是如何执行的呢 -- JS的作原理

JavaScript 到底是如何工作的? 一、工作原理 JavaScript到底是: 同步还是异步? 单线程还是多线程? JavaScript 中的一切都发生在 Execution Context (执行上下文)中 您可以假设这个执行上下文 是一个大盒子或一个容器,在其中执行整个 JavaScript 代码。 这个大盒子里有两个组件: Memory(内存组件):这是所有变量和函数存储为键值对的地方。这个**“内存组件”也称为变量环境**。因此,它是一种环境,其中所有这些变量和函数都存储为键值对。 Code(代码组件):这是代码逐行执行的地方。这个“代码组件”也称为执行线程。所以,这个执行线程是一个单线程,整个代码一次只执行一行。 结论:JavaScript 是一种同步单线程语言。 单线程 意味着 JavaScript 一次只能执行一个命令。 同步单线程 意味着 JavaScript 一次只能以特定顺序每次执行一个命令。这意味着它只能在当前行完成执行后转到下一行。这就是同步单线程的意思。 很惊诧吧,实际 javascripts 有单线程 event loop 大循环来完成很多不可思议的事情。 二、实际工作过程分析 JavaScript 代码是如何执行的? 当你运行 JavaScript 代码时会发生什么? 会创建一个Execution Context(执行上下文)。 让我们使用实际的代码来举个例子: var n = 2; function square(num) { var ans = num * num; return ans; } var square2 = square(n); var square4 = square(4); 执行上述代码时,会创建 一个执行上下文 ...

2022年06月21日 · 1 分钟 · 190 字 · 八戒

Javascripts中if的优化

Javascripts 中的 if … else 用起来倒是很方便,但是看起来就不舒服了 if (true) { } if (true) { } if (true) { if (true) { if (true) { } } else { } } else { } 上面看起来很闹心吧,下面讲讲优化: 一、三元优化 if (ture) else可以用三元操作符来优化它: // Bad 😥 if (true) { console.log("Congratutions!") } else { console.warn("Oops, something went wrong!") } // Great 🥰 true ? console.log("Congratutions") : console.warn("Oops, something went wrong!") 二、与优化 true的情况下才执行可以用与来进行优化: if (true) { alert(1) } // is equals to: true && alert(1) 三、提前返回 如果有多个判断,按照复杂程度,从上到下,提前返回。 ...

2022年06月15日 · 2 分钟 · 369 字 · 八戒

Shell进阶技巧

Shell脚本的进阶技巧: 一、String 类的技巧 String类当作数组来使用,注意范围的下标,0:4,4最后要被踢掉,实际是0-3,共4个字符: string="Bash is great!" echo ${string:8} # great! echo ${string:0:4} # Bash echo ${string:8:-1} # great (-1: upto 1st element from right) 数组的长度: string="Bash is great!"; len=${#string} echo "len = $len" 字符串的替换: string="Bash is great!!" echo ${string/Bash/GNU Bash} # GNU Bash is great!! echo ${string//!/.} # Bash is great.. 大小写替换: string="Bash" echo ${string^^} # BASH echo ${string,,} # bash 按index存取数组中字符在shell中不可用,但是可以用function变相实现: function charAt() { string=$1 i=$2 echo ${string:i:1} } echo $(charAt "Hello" 2) # l echo $(charAt "Hello" 1) # e 二、数组和字典 定义一个数组并且遍历它: ...

2022年06月09日 · 2 分钟 · 308 字 · 八戒

javascripts中的promise

一、基本概念 1. 异步 所谓 " 异步 “,简单说就是一个任务分成两段, 先执行第一段, 然后转而执行其他任务去, 等做好了准备, 再回过头执行第二段。 比如, 有一个任务是读取文件进行处理, 任务的第一段是向操作系统发出请求, 要求读取文件。 然后, 程序执行其他任务, 等到操作系统返回文件,再接着执行任务的第二段( 处理文件)。 这种不连续的执行, 就叫做异步。 相应地, 连续的执行就叫做同步。 由于是连续执行, 不能插入其他任务, 所以操作系统从硬盘读取文件的这段时间, 程序只能干等着什么也做不了。 2. 回调函数 javascript 语言对异步编程的实现, 就是回调函数。 所谓回调函数, 就是把任务的第二段单独写在一个函数里面, 等到准备好了,继续执行的时候, 就直接调用这个函数。 它的英语名字 callback, 直译过来就是 " 回调 “。 读取文件进行处理, 是这样的,readfile 是异步的,readfileSync 是同步的。 fs.readfile('/etc/passwd', function(err, data) { if(err) throw err; console.log(data); }); 上面代码中, readfile 函数的第二个参数, 就是回调函数, 也就是任务的第二段。 等到操作系统返回了 / etc / passwd这个文件以后, 回调函数才会执行。 ==一个有趣的问题是, 为什么 node.js 约定, 回调函数的第一个参数, 必须是错误对象 err( 如果没有错误, 该参数就是 null)? 原因是执行分成两段, 在这两段之间抛出的错误, 程序无法捕捉, 只能当作参数, 传入第二段。== ...

2022年05月24日 · 2 分钟 · 365 字 · 八戒

javascripts中的map

Javascripts 中的 map 说到map,如果我们有循环的话,不停遍历,会把时间搞成 O(n)。如果有map,时间就变成了O(1),所以还是相当有效率的。 map 是 ES2015 中新增加的,是一种新的 Object 类型,允许存放各种 key-value 对。 map 最大的特性是,key 可以是任何类型,包括 object 和 function;可以调用 size 得到 map 的大小;迭代的时候,是严格按照添加的顺序进行迭代的。 map 的方法如下: set, get, size, has, delete, clear: let things = new Map(); const myFunc = () => '🍕'; things.set('🚗', 'Car'); things.set('🏠', 'House'); things.set('✈️', 'Airplane'); things.set(myFunc, '😄 Key is a function!'); things.size; // 4 things.has('🚗'); // true things.has(myFunc) // true things.has(() => '🍕'); // false, not the same reference things.get(myFunc); // '😄 Key is a function!' things.delete('✈️'); things.has('✈️'); // false things.clear(); things.size; // 0 // setting key-value pairs is chainable things.set('🔧', 'Wrench') .set('🎸', 'Guitar') .set('🕹', 'Joystick'); const myMap = new Map(); // Even another map can be a key things.set(myMap, 'Oh gosh!'); things.size; // 4 things.get(myMap); // 'Oh gosh!' 迭代它的方法,可以用 for … of,顺序是严格按照你插入的顺序来的: ...

2022年05月23日 · 1 分钟 · 192 字 · 八戒

javascript的实际应用-fs模块

千里之行始于足下,javascript 模块漫天飞,能做的事也是五花八门。我们来实践一下 假设我们有一个文本文件,内容如下: 里面是一行行数据,我们要做的就是把所有值取整求和,文件中有某些空行 很简单,程序如下: var fs = require('fs'); calculate = () => { fs.readFile('data.txt', 'utf8', (err, data) => { if (err) { throw new Error(err) } const arr = data.split('\r\n'); const result = arr .filter(e => e) .map(parseFloat) .reduce((curr, next) => curr + next); console.log('RESULT: ', result); }); } 超级简单吧 关键就是上面的链式调用 split 用来分割每一行 filter 用来去掉空行 map 用来把每一行都转化成整数 reduce 用来求和

2022年05月22日 · 1 分钟 · 60 字 · 八戒

javascripts中的module

JavaScript Module 是什么 一个 JavaScript module 模块准确的说就是一个文件,它允许你把代码 export 导出来复用,这样别的 JavaScript 文件可以 import 这个文件把它作为库文件来使用了。 模块主要是用在工程文件中,用来把代码共享给其他文件用,javascipt 的模块可以说是满天飞。 这里呢讨论的是前端的部分,即是运行在浏览器中的 javascripts module 部分,而不是运行在后端的 Node.js 的部分,后端现在已经向前端靠拢了。 ES6标准发布后,module成为标准,标准使用是以export指令导出接口,以import引入模块,但是在我们一贯的node模块中,我们依然采用的是CommonJS规范,使用require引入模块,使用module.exports导出接口。这点也理解清楚。 我们从零来一步步开始吧 如何把一个 JavaScript 文件转换为 ES 的 module 1: 创建一个 project 目录 这个目录用来放 HTML 和 JavaScript 文件 2: 建立你的 code 代码文件 在 project 文件夹中建立2个文件: index.html index.js 3: 添加 JavaScript 文件的引用到 HTML 文件中 打开index.html 编辑它: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ES Module - zhang ranrui</title> </head> <body> <h1>ES Module Tutorial</h1> <!-- Add the "index.js" JavaScript file to this HTML document --> <script type="module" src="index.js"></script> </body> </html> 上面的代码中,我们引用了 index.js , 并定义它 type=“module”,这显式指明了 index.js 是一个 ES 的module。 ...

2022年05月21日 · 5 分钟 · 870 字 · 八戒

Javascripts之数组的reduce

研究一下 javascripts 的 reduce ,reduce 是既能改变 array 的 size,又能改变数值的函数,filter 是只能改变size,不能改变数值;而 map 是不能改变 size,可以改变数值。很拗口吧,三个兄弟。 简单介绍一下 reduce。 假设我们有一个数组: [1, 2, 3, 4] 我们要对整个数组求和. reduce 实际是按照下列的算式来进行求和的: ((((1) + 2) + 3) + 4) 那实际 reduce 函数执行中,你可以按你需求来自定义你自己的 + 操作符。数组的值也可以是其他的任意东西。听起来有点意思吧? 1、 Reduce 是干嘛的 在一个函数式编程语言中,reduce 其实有很多别的名称,比如 fold(对折), accumulate(累加器), aggregate(聚合器), compress(压缩) 甚至叫 inject(注入)。 2、 Reduce 的参数 常用用法如下: let myArray = [/* 首先定义一个数组 */]; let callbackfn = /* 再定义一个函数 */ ; let initialvalue = /* 任意一个初始化的值 */ ; myArray.reduce(callbackfn) myArray.reduce(callbackfn, initialValue) reduce 的参数如下: callbackfn: 必须是一个函数,会在整个数组中反复调用,reduce 调用 callbackfn 的时候有4个参数,我们定义它们是 previousValue, currentElement, index 和 array ,看起来像下面一样: ...

2022年05月20日 · 2 分钟 · 398 字 · 八戒

面试之Docker如何打出最小的镜像

面试的时候被问到:如何才能让 docker 打出的镜像包尽量小? 其实在生产已经尽量使用最小化的镜像包了,只是突然被问到还是有点懵圈;因为印象中自己基本是使用 alphine 做底包,Dockerfile 通常就是 copy 一个可执行的程序进去就完事了,如果不行,再开 shell 进去慢慢添加缺少的库文件。 这里就总结一下,两点: 一、使用尽量小的底包 以 alphine 为主,使用 alphine 底包的时候,需要注意以下: 1、替换 apk 的源 2、更新、更新证书 3、注意 Timezone 的设置 4、注意 glibc 库的兼容问题 二、使用分阶段build 通常类似c、go、rust之类的源代码,都需要经过编译,最后产生可执行文件,那么完整的编译环境其实对最后的镜像来说都是不需要的。 所以利用分阶段build,甩脱编译环境以及中间产物,就可以缩小最后 build 出镜像的大小,使用也很简单。 Dockerfile 文件内容如下: FROM golang:alpine AS build-env WORKDIR /app ADD . /app RUN cd /app && go build -o goapp FROM alpine RUN apk update && \ apk add ca-certificates && \ update-ca-certificates && \ rm -rf /var/cache/apk/* WORKDIR /app COPY --from=build-env /app/goapp /app EXPOSE 8080 ENTRYPOINT ./goapp

2022年04月01日 · 1 分钟 · 80 字 · 八戒

面试之Nginx的epoll的优势

面试时被问到:是否了解 Nginx,它使用的 epoll 模式和其他的相比有什么优势? 直接被问住,实际生产中配过不少的 Nginx,各种 rewrite、regex、正反向代理、php、fast-cgi、限流、证书、jwt、cors;epoll 只大概有印象是下面这行: events { use epoll; worker_connections 1024; } 实在是汗颜啊,所以得仔细研究一下这个 epoll。 首先扔概念 IO多路复用: 多路是指网络连接,复用指的是同一个线程。 IO多路复用是一种同步IO模型,实现一个线程可以监视多个文件描述符; 一旦某个描述符就绪(一般是读就绪或者写就绪),就能够通知应用程序进行相应的读写操作; 没有文件描述符就绪时会阻塞应用程序,交出cpu。 那么IO多路复用的实现方法有三种: select、poll、epoll select、poll、epoll本质上都是同步I/O,用户进程(这里就是Nginx)负责读写(从内核空间拷贝到用户空间),读写过程中,用户进程是阻塞的。 select: 查询 fd_set 中,是否有就绪的 fd,可以设定一个超时时间,当有 fd (File descripter) 就绪或超时返回; fd_set 是一个位集合,大小是在编译内核时的常量,默认大小为 1024 特点: 连接数限制,fd_set 可表示的 fd 数量太小了; 线性扫描:判断 fd 是否就绪,需要遍历一边 fd_set; 数据复制:从内核空间拷贝到用户空间,复制连接就绪状态信息 poll: 解决了连接数限制: poll 中将 select 中的 fd_set 替换成了一个 pollfd 数组 解决 fd 数量过小的问题 数据复制:从内核空间拷贝到用户空间,复制连接就绪状态信息 epoll:event 事件驱动 事件机制:避免线性扫描 为每个 fd,注册一个监听事件 fd 变更为就绪时,将 fd 添加到就绪链表 ...

2022年04月01日 · 1 分钟 · 129 字 · 八戒