2016年6月

从输入 URL 到页面展示

本文从网络层以上讨论从浏览器输入 HTTPS 协议的 URL 到页面展现的全过程。由于不同浏览器之间也存在差异,这里以 Chrome 浏览器为例。

1. DNS查询

DNS 缓存有好几个环节,浏览器缓存,系统缓存,路由器缓存,ISP 缓存。

  • 浏览器首先会查看自身是否已经有进行 DNS 缓存。Chrome 可以通过 chrome://net-internals/#dns 查看缓存的 DNS,浏览器的 DNS 缓存可以加快 DNS 解析速度,但缓存时间不会太长。

    Chrome 的 DNS 缓存

  • 如果浏览器没有相应的缓存,则查找系统缓存,浏览器会向系统发送一个查询请求,如果系统存在缓存或者设置了 host ,则返回相应的 ip 地址给浏览器。

  • 如果系统没有缓存,那么它会发出一个 DNS 查询请求给路由器。

    如果路由器有 DNS 缓存,他会提取出 IP 地址返回。否则,他会向本地域名服务器发出查询,从请求主机到本地域名服务器的请求一般是递归查询,而其他的查询一般是迭代查询。

    DNS 请求主机到本地域名服务器的查询

    DNS 域名服务器之间的查询

    请求报文如下

    DNS 请求报文

    我们先简单分析下请求报文。

    1. DNS 使用 UDP 协议,端口号53。
    2. 在 DNS 报文的 Flags 中的 RD=1。表示它建议域名服务器以递归方式查询。
    3. Question section format 需要给出 QNAME, QTYPE, QCLASS。即查询的域名,查询的类型以及查询的类。

    有关DNS报文的更多信息可以参考RFC1035

    响应报文如下

    DNS 响应报文

    我们也简单分析下,如果想详细了解,可以查看上面的 RFC1035 标准。

    1. 与请求报文相比,对比 Flags 可以发现,QR=1 表示这是一个响应报文。RA=1 表示递归查询可用。
    2. ARecord 记录了DNS请求获得的一个或多个IP地址。一般还会得到 CNAME 记录和存活时间等信息。
    3. 这里对 Rcode 也稍加说明下,Rcode=0 表示成功,他还有好几种状态码,比如1表示 Format error,2表示 Server failure,3表示 Name error,4表示 Not lmplemented,5表示 Refused,具体信息可以参考 RFC1035

- 阅读剩余部分 -

Angular 学习总结

这学期基本都是在学习和使用 Angular ,这篇文章主要是想介绍几个 Angular 需要注意或者了解的地方。

Angular作用域

​ 也许你知道 ng-if 和 ng-show 的区别是一个只有条件满足的时候才会创建 DOM ,一个是只有在条件满足的时候才会显示 DOM 也就是一开始也会跟着创建。但是你可能不知道, ng-if 会产生新的作用域, ng-repeat 和 ng-switch 和 ng-include 也是如此。这时候内部如果使用外部的变量,第一次的时候会正常显示,因为 Angular 的继承是原型链继承,如果子类没有这个属性就会去尝试继承父类的属性, Angular 会拿父类的属性来创建新的属于这个子类的属性,而这个属性将不再和外层的父类的属性挂钩,如果不注意很可能就会在这里踩坑。

读子类的属性时,子类有这个属性(hasOwnProperty)的时候则读子类自己的,子类没有的时候读父类的,不管子类有没有这个属性,在子类上都不会有新属性被创建。

写子类的属性时,如果子类有这个属性(hasOwnProperty)则写子类的,子类没有的话就会在子类上新建一个同名的新属性,而父类继承过来的属性被隐藏。

​ 关于原型链继承这个可以参考此处JavaScript Prototypal Inheritance,或者[译文] 深入浅出 AngularJS 作用域

​ 使用上述的 ng-if , ng-repeat , ng-switch , ng-include 都会自己创建一级作用域,这点一定要注意。如果想要和父类的属性挂钩,可以使用 $parent 。

​ 但是,还没玩,也许这些你都知道。但是除了这些指令之外, textarea 也会自己创建一级作用域。所以你可能会发现你在 textarea 写的内容获取不到,但是却发现 textarea 总能取到第一次分配的初值。比如

<textarea ng-model="content", name="content" class="form-control" row="3"></textarea>

​ 我们在控制器里面定义

$scope.content = "测试"

​ 然后我们就会看到 textarea 的初值为"测试",但是当我们更改其中的内容之后, $scope.content 却一直保持不变。

​ 同样,我们可以使用 $parent 的方式来解决这个问题。

<textarea ng-model="$parent.content", name="content" class="form-control" row="3"></textarea>

​ 那如果不想使用 $parent 的话,可以给 content 分配一个类名,比如

<textarea ng-model="comment.content", name="content" class="form-control" row="3"></textarea>

​ 这样我们就可以通过 $scope.comment.content 来取值。

Angular track by

​ 在使用 Angular 的 ng-repeat 迭代数组时,有时候会出现 Duplicates in a repeater are not allowed 的提示。

​ track by 是用来建立 $watchCollection 和 DOM 之间的联系。建议自己加上 track by 后面带的值可以自己写,但要确保每个 ngRepeat 的值唯一,比如可以写 track by $index 。

​ 之所以要这么做,是因为,如果不使用 track by ,那么每个 ng-repeat 都会添加一个 $$hashkey 来对的 DOM 进行跟踪,这样会导致不能存在相同的 DOM ,使用 track by 的意义是避免不必要的渲染。

​ 官网API有进行详细的说明,不过我看了之后还是感觉不太明白,等我了解清楚了再来补充下。AngularJS: API: ngRepeat

If you are working with objects that have an identifier property, you should track by the identifier instead of the whole object. Should you reload your data later,  ngRepeat  will not have to rebuild the DOM elements for items it has already rendered, even if the JavaScript objects in the collection have been substituted for new ones. For large collections, this significantly improves rendering performance. If you don't have a unique identifier,  track by $index  can also provide a performance boost.

Angular拦截器

​ Angular 拦截器是 Angular 的一个强大功能,不过暂时没有怎么去研究,简单说下我的一些使用。

- 阅读剩余部分 -

谈谈前端自动构建工具 Gulp

类似 Gulp 这样的工具可以说是前端利器,基本前端开发都离不开他,类似的解决方案还有 Grunt 和 Webpack 等,不过我用 Gulp 比较多一些,所以我只能谈谈 Gulp 了。

Gulp 上面优秀的插件特别多,我使用的有这些:

import gulp from 'gulp'
import babel from 'gulp-babel'
import uglify from 'gulp-uglify'
import ngAnnotate from 'gulp-ng-annotate'
import concat from 'gulp-concat'
import cleanCSS from 'gulp-clean-css'
import imagemin from 'gulp-imagemin'
import minifyHtml from 'gulp-minify-html'
import ngTemplate from 'gulp-ng-template'
import plumber from 'gulp-plumber'
import sass from 'gulp-sass'
import usemin from 'gulp-usemin'
import runSequence from 'gulp-run-sequence'
import eslint from 'gulp-eslint'
  • gulp-uglify
    对 JavaScript 进行压缩的插件,可以有效减少 JavaScript 的文件大小。
  • gulp-ng-annotate
    对 Angular 的代码进行转换,因为使用上面的 gulp-uglify 对 Angular 的代码进行压缩时会破坏 Angular 文件的依赖注入功能,导致无法正常工作,这个基本上是 Angular 开发必备的了。
  • gulp-concat
    文件合并,前端合并文件以减少请求是非常重要的优化技巧。
  • gulp-clean-css
    字如其名,对css 进行合并压缩。
  • gulp-imagemin
    对图片进行压缩。
  • gulp-minify-html
    对html文件进行压缩。
  • gulp-ng-template
    这个也是 Angular 里面比较响当当的一个插件了,他的作用是将 Angular 模板存到 templateCache ,可以提升模板加载速度。
  • gulp-plumber
    这个貌似也是 Gulp 必不可少的插件之一了,可以避免 Gulp 出错导致整个进程崩掉。
  • gulp-sass
    编译 sass 代码为 css,非常方便。
  • gulp-run-sequence
    可以让 Gulp 的任务顺序执行,有些时候我们希望 Gulp 执行了一些任务完成之后才来执行下一个任务,这时候这个插件就派上用场了。
  • gulp-usemin
    这个是用来从工作环境到生产环境进行部署的工具。
  • gulp-eslint
    eslint 代码检查。

- 阅读剩余部分 -