blog
blog copied to clipboard
个人博客
> 内容分发网络(Content delivery network或Content distribution network,缩写:CDN)是指一种通过互联网互相连接的电脑网络系统,利用最靠近每位用户的服务器,更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户。 ### 为什么需要CDN 根本上的原因是,访问速度对互联网应用的用户体验、口碑、甚至说直接的营收都有巨大的影响,任何的企业都渴望自己站点有更快的访问速度。而HTTP传输时延对web的访问速度的影响很大,在绝大多数情况下是起决定性作用的,这是由TCP/IP协议的一些特点决定的。物理层上的原因是光速有限、信道有限,协议上的原因有丢包、慢启动、拥塞控制等。 要提高访问速度,最简单的做法当然就是多设置几个服务器,让终端用户离服务器“更近”。典型的例子是各类下载网站在不同地域不同运营商设置镜像站,或者是像Google那样设置多个数据中心。但是多设几个服务器的问题也不少,一是多地部署时的困难,二是一致性没法保障,三则是管理困难、成本很高。实际上,在排除多地容灾等特殊需求的情况下,对大多数公司这种做法是不太可取的。当然,这种方案真正做好了,甚至是比后续所说的使用CDN要好的。 CDN是一种公共服务,他本身有很多台位于不同地域、接入不同运营商的服务器,而所谓的使用CDN实质上就是让CDN作为网站的门面,用户访问到的是CDN服务器,而不是直接访问到网站。由于CDN内部对TCP的优化、对静态资源的缓存、预取,加上用户访问CDN时,会被智能地分配到最近的节点,降低大量延迟,让访问速度可以得到很大提升。 ### CDN的原理 > CDN做了两件事,一是让用户访问最近的节点,二是从缓存或者源站获取资源 CDN有个源站的概念,源站就是提供内容的站点(网站的真实服务器), 从源站取内容的过程叫做回源。 每次访问的具体流程如图(以最普通的CDN为例)  具体举个例子: 用户在首次访问 [https://assets-cdn.github.com/pinned-octocat.svg](hhttps://assets-cdn.github.com/pinned-octocat.svg) , 假设不委托local DNS服务器递归查询,会经历以下几个过程 1. 浏览器检查本地有没有这个东东的有效缓存,有则使用缓存,没有有效缓存则进行对`assets-cdn.github.com`的DNS查询,获得一个 CNAME记录, `igithub.map.fastly.net`,值得注意的是,多个加速域名可以解析到同一个CNAME,CDN回源和缓存的时候考虑到了hostname,👍; 2....
> 副标题:在onClick中调用setState会发生什么? 现在版本的React(16.2)用了`fiber`,网上也说的很多,但实质上React就是把对树的遍历由递归改成了循环,把数组换成了链表。而所谓的`fiber`--也就是所谓的`virtual stack frame`则是把栈帧的组织方式由栈变成了链表而已。递归被撤掉,加上引入的一系列新特性(call, return, 甚至fragment)让React源代码显得比较碎片化,以至于只能自己动手去观赏源码。 下面是一个很简单(无聊)的React应用: ````jsx import React, { Component } from 'react'; import { render } from 'react-dom'; class Comp1 extends Component { constructor(props) { super(props);...
> 该书有点年代,讲的OC都是不带ARC的。用Xcode9的话,书中的例子甚至都不能通过编译,网上也鲜有人提及修改的方法,在此把折腾的东西做个记录。 P87 中提及了“利用该机消息枚举”,实质是给容器生成一个代理对象,而向代理对象发送消息的话会将消息转发到容器中的每一个对象,并将调用的结果存入数组中返回。 修改后可通过编译的代码如下: NSArray+map.h ````objective-c #import @interface NSArray (AllElements) - (id) map; @end @interface NSArrayMapProxy: NSProxy { NSArray* array; } - (instancetype) initWithArray: (NSArray*) anArray; @end ```` NSArray+map.m...
HTTP缓存
首先,HTTPS的缓存和HTTP的缓存策略是相同的,都是由HTTP响应头决定。 ## Cache-Control > 请求头和响应头都可以设定该字段,用于控制缓存链的行为;这是个单向指令,也就是请求和响应头中的`Cache-Control`独立控制请求和响应;不管代理能不能理解这些指令都应该原封不动地传递。`Age`是与之紧密相关的字段,表示响应由源站生成或确认的时间与当前时间的差值。指令如下: ### 请求 #### 1. max-age 简而言之,指定保质期的指令。`max-age`指令标示了客户端不愿意接收一个`age`大于设定时间的响应。除非还指定了`max-stale`,否则客户端是不会接收过期的响应的。 某些浏览器(比如Firefox)中如果设定为永不缓存,那么其发出的请求中,请求头会包含`max-age=0`。 #### 2.max-stale 字面意思,能容忍的最大过期时间。`max-stale`指令标示了客户端愿意接收一个已经过期了的响应。如果指定了`max-stale`的值,则最大容忍时间为对应的秒数。如果没有指定,那么说明浏览器愿意接收任何`age`的响应。 暂时没有发现比较常见的使用场景。 #### 3.min-fresh 设定能够容忍的最小**新鲜度**。`min-fresh`标示了客户端不愿意接受**新鲜度**不多于当前的`age`加上`min-fresh`设定的时间之和的响应。 #### 4.no-cache `no-cache`指令标示了缓存链禁止返回一个未经源站验证的缓存响应。 已知的是Chrome勾掉`disable cache`之后,所用的请求都会带有这个字段。可惜的是这个指令对于CDN来说,往往没有什么用处,并不会回源,可能是CDN并不认为自己是个代理。 #### 5.no-store cache禁止存储请求和响应中的任何部分。这个指令被用于`private`和`shared`的cache中。“禁止存储”在这个上下文中是指cache禁止在非易失存储设备中存储信息,并且必须尽最大努力在转发请求/响应之后移除这些信息。 这个指令并不是一个可靠和有效保证隐私的措施。特别是,恶意的或者妥协的cache并不会识别或者遵守这个指令,并且互联网通信是很可能被窃听。 啊哈,如果运营商啥的遵守这个指令,就不会有信息贩卖这回事了。 ####...
网上谈Node C++扩展的文章种类比较单一,基本上都是在说怎么去写扩展,而对模块本身的解读相当少,笔者恰巧拜读了相关代码,在此做个记录。 > 注: 文中的“原生模块”均是指代C++模块 ### Node如何加载原生模块 朴灵老师的《深入浅出Node.js》一书其实有谈过这个问题,但是随着Node项目的演进,已经发生了一些微妙的变化。 原生模块被存在链表中,原生模块的定义为: ````cc struct node_module { // 表示node的ABI版本号,node本身导出的符号极少,所以变更基本上由v8、libuv等依赖引起 // 引入模块时,node会检查ABI版本号 // 这货基本跟v8对应的Chrome版本号一样 int nm_version; // 暂时只有NM_F_BUILTIN和0俩玩意 unsigned int nm_flags; // 存动态链接库的句柄 void* nm_dso_handle;...
我们常常听说JavaScript是一门基于原型的面向对象语言,然后也有一堆说“原型”的文章,不过大都是列举一下用法,说说原型链,就完了。至于究竟“原型”是什么,语义是什么,甚少有文章会提到。 > 原型这个词其实是非常中肯的。 ## 简述 写程序的都知道“原型”这个东西,就是万恶的产品经理经常搞的那个嘛~假设产品经理是用的Sketch做的原型,那么设计会从产品经理那儿拷贝一份产品经理做好的原型,然后在上面修改(当然不一定这么干,不过可以这么干就是了),最后的苦逼的小前端就会基于设计给出的设计稿生成页面。 我们可以这么说,设计做的事情是把原型改成设计稿, 而小前端做的则是把设计稿作为参考生成html/css/js。而JavaScript中的原型,也差不是这个理,也就是用来`复制一个副本 & 在副本的基础上修改`。所以说原型这个词是比较中肯的。 ## 起源 从网上都能找到JavaScript里基于原型的面向对象(Prototype-based oo)的起源,Self语言(真正的起源其实应该是actor,不过这货资料极其稀有)。这个小众的Self语言,网上没什么资料。 在只言片语中,可以找出一些Self语言中的重要信息: - Self中一切都是对象,对象有数个slot(slot是一个方法或数据,跟js的属性有点类似) - Self中新建对象的方法为复制现有对象,再酌情增删改slot `oldObj copy newProp: 'Hello, World!'.` - Self中被复制的对象可以叫做prototype,因为原对象并不完善,要复制一份出来修修补补 - Self中可以明确地选取slot指明parent属性,以供delegation 另外有一篇paper讨论了delegation(委托)和inheritance(继承)分别实现prototypal 和...
> 基于11.27日的草案版本,[在线地址](https://w3c.github.io/workers/) ## 摘要 这份Spec定义了一个API,这个API使web应用开发者能够生成与他们的主页面并行的、在后台运行的worker脚本。这也使得,只要将消息传递作为协作机制,就能实现类线程的操作。 ## 1. 简介 ### 1.1. 范畴 _本节是非正式的_ 这份Spec定义了一个用于运行与用户界面脚本独立的后台脚本的API。 这使得持续运行一些脚本,而不被响应点击或者其他用户交互的脚本打断,成为可能。而且,也使得长时任务可以被持续运行,而不用让出调度权来使得页面保持响应性。 Worker(这些后台脚本就叫这个)是相对而言比较重的,并且也不想被大规模地创建出来。例如,为一个4M大小的图片的每个像素创建一个worker是不合适的。下面的例子将展示一些worker恰当的用法。 一般而言,worker具有较长的存活期,有一个比较大的启动性能开销并且每个实例有略高的内存消耗。 ### 1.2. 示例 _本节是非正式的_ worker有许多用途。下述子章节展示了几种用途。 #### 1.2.1. 进行后台数值运算的worker _本节是非正式的_ worker最简单的用途是,运行计算密集型任务而不打断用户的交互。 在这个例子中,主文档派生一个worker(naively)来计算素数,并展示最近被找到的素数。 住文档页面如下所述: >示例1 main.html...
* Haskell实现算法都是递归,一切都可递归 * 一切都是函数,就连list也只是对某种类型的构造函数 * 函数都只能接受一个参数,“多个参数”只是多出了curry的可能性
[karma](http://karma-runner.github.io/1.0/index.html)是一个著名的浏览器测试框架,他的特色是启动一个nodejs服务器,在浏览器端通过http下载脚本,并通过websocket实现karma和浏览器实现双向通信。 网上甚少有使用karma做mock的教程。但是因为karma使用了connect模块,有中间件的能力,因此值得一试。 ## 引入karma karma官方支持的是jasmine,所以省事一点就直接用jasmine(不过这货返回promise没有官方支持)。 * 在项目中新建文件karma.conf.js ````js module.exports = config => { config.set({ basePath: './test', files: ['**/*.spec.js'], browsers : [ 'Chrome', ], frameworks: ['jasmine'], singleRun: true, }); } ````...
在JavaScript中,`call/apply`是函数原型上的方法,作用是指定函数的context也就是所谓的`this`变量。JavaScript中`this`的指向“不明”饱受诟病然而,实际上`this`的指向十分清晰,`this`永远指向函数的调用者,而`call/apply`的作用可以简单地说成了强行更改调用者。 不过,为什么好像其他常用的语言中没有出现this的混淆和`call/apply`这种函数呢?实际上,门门语言都有这个问题,因为从根本上说,`this`本身就只能通过当做参数来传入,我们的计算机底层只能调用函数/过程,只是,其他语言都是会有隐式绑定,也就是类似于箭头函数的行为的。 下面是几个语言this实现举例,其中大都涉及到面向对象的实现机制: #### Java的实现 嗯,Java是个纯粹的面向对象语言,基于class。使用Java的时候,要显式使用this的场景,只有函数形参或者局部变量和类的成员变量名冲突的时候。 假设我们有这样一个类: ``` class Hello { Hello() { } public void sayHello () { say("Hello, world!"); } private void say(String str) { System.out.println(str); } public...