理解 JavaScript 异步编程
一。单线程我们常说 “JavaScript 是单线程的”。
所谓单线程,是指在 JS 引擎中负责解释和执行 JavaScript 代码的线程只有一个。不妨叫它 主线程 。
但是实际上还存在其他的线程。例如:处理 AJAX 请求的线程、处理 DOM 事件的线程、定时器线程、读写文件的线程 (例如在 Node.js 中) 等等。这些线程可能存在于 JS 引擎之内,也可能存在于 JS 引擎之外,在此我们不做区分。不妨叫它们 工作线程 。
二。同步和异步假设存在一个函数 A:
1A (args...);
同步 :如果在函数 A 返回的时候,调用者就能够得到预期结果 (即拿到了预期的返回值或者看到了预期的效果),那么这个函数就是同步的。
例如:
12Math.sqrt (2);console.log ('Hi');
第一个函数返回时,就拿到了预期的返回值:2 的平方根。
第二个函数返回时,就看到了预期的效果:在控制台打印了一个字符串。
所以这两个函数都是同步的。
异步 :如果在函数 A 返回的时候,调用者还不能够得到预期结果,而是需要在将来通过一定的手段得到,那 ...
Web - 从 url 到页面发生了什么
访问过程我们在浏览器地址栏中输入 google.com 这个地址,然后浏览器经过短暂加载后给我们呈现了 Google 的搜索页面。
这中间的步骤有哪些呢?
首先是域名解析 google.com 转换为这个网站服务器的 IP,这其中或许还包含有 CDN 加速、负载均衡,分布式服务等技术。
获取到服务器 IP 之后,我们的浏览器会通过 TCP 三次握手与服务器建立 TCP 连接。
如果网站是 HTTPS,还会经过 TLS/SSL 的握手步骤与服务器建立 TLS/SSL 连接。
建立 TCP 连接之后,浏览器作为客户端发送 HTTP 请求 (request) 报文到目的 IP 地址即 Web 服务器 IP。
有的时候获取的 IP 是反向代理的服务器 IP,这些服务器接受客户端请求,并把请求转发给真实服务器 IP。
接下来是服务器的工作过程:
服务器上 Google.com 服务进程监听服务端口,收到客户端的 HTTP 请求报文,这个报文被服务器上安装的 Web 服务器 (Web Server) 如 apache、nginx、LigHTTPd、IIS 所监听到。
Web Se ...
MySQL 命令之 Explain 笔记
MySQL 提供了一个 EXPLAIN 命令, 它可以对 SELECT 语句进行分析, 并输出 SELECT 执行的详细信息, 以供开发人员针对性优化。借助一个实例操作,来对 Explain 用法做一些总结。
简介EXPLAIN 命令用法十分简单, 在 SELECT 语句前加上 Explain 就可以了, 例如:
1EXPLAIN SELECT * from user_info WHERE id < 300;
准备为了接下来方便演示 EXPLAIN 的使用, 首先我们需要建立两个测试用的表, 并添加相应的数据:
12345678910111213141516171819202122232425262728293031323334353637383940CREATE TABLE `user_info` ( `id` BIGINT (20) NOT NULL AUTO_INCREMENT, `name` VARCHAR (50) NOT NULL DEFAULT '', `age` INT (11) DEFAULT NUL ...
JavaScript 的事件模型
监听函数浏览器的事件模型,就是通过监听函数(listener)对事件做出反应。事件发生后,浏览器监听到了这个事件,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。
JavaScript 有三种方法,可以为事件绑定监听函数。
HTML 的 on- 属性HTML 语言允许在元素的属性中,直接定义某些事件的监听代码。
12<body onload="doSomething ()"><div onclick="console.log (' 触发事件 ')">
上面代码为 body 节点的 load 事件、div 节点的 click 事件,指定了监听代码。一旦事件发生,就会执行这段代码。
元素的事件监听属性,都是 on 加上事件名,比如 onload 就是 on + load,表示 load 事件的监听代码。
注意,这些属性的值是将会执行的代码,而不是一个函数。
12345<!-- 正确 --><body onload="doSomething ...
HTTPS 原理解析
HTTP 协议是明文传输,它简单易于理解,但同时也带来了安全性问题,在复杂的网络环境中,HTTP 流量几乎是在裸奔,可以轻易被监听,为了解决这个问题,人们提出了 HTTP over SSL 即 HTTPS,即通过 ssl 隧道来传输 HTTP 流量,这样加密了 HTTP 数据包,实现了传输链路上的安全性。相比于 HTTP,HTTPS 在 TCP 层上多了一个 SSL/TLS 层。
HTTPS 的通信过程SSL/TLS
SSL(Secure Socket Layer,安全套接字层):1994 年为 Netscape 所研发,SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。
TLS(Transport Layer Security,传输层安全):其前身是 SSL,它最初的几个版本(SSL 1.0、SSL 2.0、SSL 3.0)由网景公司开发,1999 年从 3.1 开始被 IETF 标准化并改名,发展至今已经有 TLS 1.0、TLS 1.1、TLS 1.2 三个版本。SSL3.0 和 TLS1.0 由于存在安全漏洞,已经很少被使用到。TLS 1.3 ...
JavaScript 中的 this
我们由一段代码开始本文的主题。
123456789101112var obj = { foo: function () { console.log(this.bar) }, bar: 1};var foo = obj.foo;var bar = 2;foo === obj.foo //trueobj.foo() // 1foo() // 2
可以看到,foo 和 obj.foo 实际上是严格相等的,它们是指向同一个代码段。由于 上下文环境 不同,所以他们运行的结果也不一样。obj.foo 的上下文环境就是 this 指向的 obj,而 foo 的上下文环境是全局环境。
JavaScript 的内存数据结构我们需要深入到 JavaScript 的内存数据结构去寻找答案。
1let obj = { foo:1 };
我们把一个对象 { foo:1 } 赋值给对象 obj。这个过程实际上是 JavaScript 引擎在内存中生成一个 { foo:1 } 然后再把这个对 ...
JavaScript 中的 call、apply 和 bind
apply & call
在 JavaScript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的
在 JavaScript 中,一切都是对象 ,包括函数。函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
例:
1234567891011function people() {} people.prototype = { name: "ming", say: function() { console.log("My name is " + this.name); }} var a = new people;a.say(); //My name is ming
此时我们有一个对象 b={name:"su"},不想重新定义 say 方法, 那么可以通过 call 或者 apply 方法。
12345b={ name: ...
Docker 管理常用命令
Docker 的常用命令一般分为:镜像管理、容器管理。
镜像管理命令下面使用 busybox 软件作为示例,busybox 软件是一个集成了非常多最常用的 Linux 命令和工具的软件集合。
查看所有镜像1docker images
REPOSITORY:镜像来自哪个仓库
TAG:镜像的标签信息,版本之类的信息
IMAGE ID:镜像创建时的 id
CREATED:镜像创建的时间
SIZE:镜像文件大小
下载软件镜像
1docker pull busybox:latest
备注:latest 表示使用 busybox 软件的最新版本,所以软件默认下载都是 latest 版本。
导出镜像1docker save busybox > busybox.tar
备注:把 busybox 镜像导出为 busybox.tar 文件,可以把 busybox.tar 文件复制到别的操作系统上使用,免除下载时网络慢的问题。
删除镜像1docker rmi busybox:latest
备注:镜像一般都会根据版本打包,如果有下载一个软件的多个版本就需要指定具体版本信息。如 busybox:1. ...
从同步编程到异步编程
虽然我们生活在一个异步的世界里,但对于多数编程初学者来说,异步还是很陌生。学习一门编程语言,通常都是从同步流程开始的,即顺序、分支和循环。而异步流程是什么呢 —— 开始一个异步调用,然后…… 就没有然后了。异步程序跑哪去了?
异步程序会以某种异步的形式在运行着,比如多线程、异步 IO 等,直到处理完成。那如果需要处理结果怎么办?给一个程序入口,让它处理完当前过程之后,把处理结果送到这个入口,然后执行另一段程序 —— 俗称回调。回调一般使用 callback 这个名称,不过有时候我更喜欢使用 next,因为它代表着下一个处理步骤。
同步和异步的概念现在我们接触到了一些概念,比如同步和异步,它们是什么?
这两个概念并不来源于编程语言,而是来源于低层指令,甚至更低层的 —— 电路。它们是基于时序的两个概念,其中,“步” 是指步调,所以同步表示相同的步调,而异步表示不同的步调。当然这两个概念提升到程序这个级别的时候,精确的意思与时钟无关,但所表示的意义仍然未变。
同步举个生活中的例子来说明这个问题 —— 排除买票。售票厅开了一个窗口,有一队人在排队依次买票。这个队伍中,前面一个人往前走了一步 ...
排序之堆排序与 JavaScript 实现
成堆 Heapify对于一个给定的数组,我们不一定实现堆这个类,而是通过 成堆 (Heapify) 这样的操作来使得数组具有堆的性质。
如图所示,要使得这个数组所对应的完全二叉树形成一个最大堆,只需要使得每一棵子树都形成最大堆即可。那么不难看出,所有的叶子结点都可以看作是一个仅有一个元素的最大堆,所以我们只需要从最后一个非叶子结点开始,通过前一节的 shiftDown 操作,就可以很容易的构建出最大堆来。
一个显而易见的数学关系是:完全二叉树最后一个非叶子节点的索引是 $n\div {2}$,例如这里有 10 个元素,那么最后一个非叶子结点的索引就是 5;类似的,如果有 11 个元素,那么同样 5 是最后一个非叶子结点的索引;不过要注意的是,这里的索引是从 1 开始的,如果是从 0 开始的索引只需使 i-1 ($n\div {2}-1$) 即可。这很容易就能用数学归纳法证明。
简单来说,Heapify 的算法过程可以简述为:
从最后一个非叶子结点开始向前遍历数组;
每遇到一个非叶子结点,就通过 shiftDown 使以当前节点为根结点的子树成最大堆;
重复直到根节点完成 sh ...