《了不起的 JavaScript 工程师 - 电子书》

JavaScript 引擎机制

多线程中较麻烦的问题是“死锁”(多个线程占用对方资源且不释放)和“惊群”(多个线程响应同一个问题)。为了降低浏览器多线程的复杂度,避免 JavaScript 引擎和渲染引擎同时操作 DOM,浏览器设计了一种机制,在某一时刻只有一个线程可以操作 DOM,也就是说 JavaScript 引擎和渲染引擎(内核)会互相阻塞

如果页面引用的 js 文件执行时间较长,或由于网络原因造成下载 js 文件时间太长,那么浏览器会长时间出于白屏状态,造成较差的用户体验。这也是把 script 标签放到 body 标签尾部的原因,可以等渲染页面结束后再执行 js 引擎。

js 单线程如何实现异步

题外话:依赖浏览器的多线程机制

现代浏览器提供 service worker 的方式让 js 异步执行

数据持久层

  • Cookie

历史最悠久,虽然是浏览器端离线存储方式,但更多用在服务器端读写。服务器端可以在响应头设置 Cookie 或从请求头读取 Cookie。如果服务器端设置了 HttpOnly 属性,浏览器端只能查看不能修改。

  • LocalStorage / SessionStorage

以键值对的方式存储数据,数据类型为字符串。SessionStorage 会在浏览器关闭后清除,LocalStorage 需要手动清除。

模板引擎

Pug 和 FreeMarker

普通文档流

在 W3C 规范中其实叫 normal flow

遵循普通文档流的元素 position 属性值为 static。根据 display 属性值的不同还会分为 none、inline、inline-block 和 block。

  • inline:宽度由内容决定,高度由font-size决定 。左右 padding 和 margin 有效,上下 padding 不占实际空间,上下 margin 无效。
  • inline-block:宽高,padding 和 margin 都可以设置。特点 是 inline-block 元素之间会出现间距,可以通过将父元素 font-size 设为 0 解决。
  • block:宽高,padding 和 margin 都可以设置。特点 是宽度以父元素为基准自动撑满整行

浮动布局

  • 两列布局

左侧宽度固定,右侧宽度自适应

<div class='left'></div>
<div class='right'></div>
.left {
  float: left;
  height: 100px;
  width: 100px;
  background-color: #f00;
}
.right {
  height: 100px;
  margin-left: 100px;
  background-color: #0f0;
}
  • 圣杯布局

中间元素设 margin,两边元素定位 + margin-left

<div class="container">
  <div class="center col"></div>
  <div class="left col"></div>
  <div class="right col"></div>
</div>
.container {
  padding-left: 200px;
  padding-right: 150px;
  overflow: auto;
}

.col {
  float: left;
  position: relative;
  height: 200px;
}

.center {
  width: 100%;
  background-color: #f00;
}

.left {
  right: 200px;
  margin-left: -100%;
  width: 200px;
  background-color: #0f0;
}

.right {
  left: 150px;
  margin-left: -150px;
  width: 150px;
  background-color: #00f;
}
  • 双飞翼布局

当圣杯布局中间元素宽度小于左侧元素时布局会错乱。双飞翼布局就是针对这个问题提出的,该布局给中间元素加一个父容器,并使用 margin 给两边留出空间。

<div class="container">
  <div class="wrap col">
    <div class="center"></div>
  </div>
  <div class="left col"></div>
  <div class="right col"></div>
</div>
* {
  box-sizing: border-box;
}

.container {
  position: relative;
}

.col {
  float: left;
  height: 200px;
}

.wrap {
  width: 100%;
}

.center {
  margin-left: 200px;
  margin-right: 150px;
  height: 200px;
  border: 1px solid #f00;
}

.left {
  margin-left: -100%;
  width: 200px;
  border: 1px solid #0f0;
}

.right {
  margin-left: -150px;
  width: 150px;
  border: 1px solid #00f;
}

样式文件命名

先按照优化后的面向属性原则来抽取公共样式,然后针对各个公共组件按照 BEM 或 AMCSS 原则命名。

前端角度解决跨域

  1. JSONP(JSON with Padding)

虽然 AJAX 请求必须同源,但 HTML 上通过标签请求的资源比如 CSS 样式文件、图片文件、JS 脚本等可以不同源。因此可以创建一个 script 标签指向一个 CDN 服务器,脚本内部通常声明一个函数或变量以供调用,浏览器识别标签后向指定网站发送 GET 请求获得脚本内容并执行。

  1. CORS(Cross-Origin Resource Sharing)

虽然浏览器默认采用同源策略,但 W3C 还是开了个后门叫做 “跨域资源共享” 。这种跨域方式需要前后端同时支持,并在返回头部字段做修改。同时针对简单请求和非简单请求需要分别处理。

  • 简单请求

请求方法:GET、HEAD、POST
浏览器发送请求时会在头部 Origin 字段带上本次请求的 “源” 信息(协议 + 域名 + 端口),服务器端会返回能够接收的源

  • 非简单请求

在发送前先使用 OPTIONS 方法发起一个预检请求到服务器端,以获知服务器端是否允许该请求。预检请求可以避免跨域请求对服务器端的用户数据产生影响。
只有得到服务器端确认允许后才可以发送请求。

  1. WebSocket

WebSocket 和 HTTP 一样,也是基于 TCP 的一种网络协议。WS 没有同源权限,不过一般用来解决浏览器和服务器端的双向通信问题。

  1. 反向代理

反向指的是转发规则对客户端不可知,用户不知道后端地址。
利用代理服务器响应客户端请求。它的原理就是服务器端之间的通信是没有同源策略和跨域之说的,只不过要对代理服务器配置对应转发规则。

高效编写/组织代码的心法

  1. 拆分 —— 基于逻辑功能对代码拆分
  2. 抽象 —— 集合常用功能对代码抽象

模块管理

  • 立即执行函数表达式

函数独有作用域。无法形成模块暴露,只能通过全局对象实现。

  • 异步模块定义(AMD)

使用 define 函数定义模块和声明依赖。在声明 myModule 的时候会开始加载 moduleA 和 moduleB,但不能保证加载顺序。只支持浏览器端

define('myModule', ['moduleA', 'moduleB'], function() { ... })
  • 共同模块定义(CMD)

使用 define 函数定义模块。在定义模块的时候会给声明函数注入 3 个参数 require、exports、module,require 用来动态引入模块,exports 用来暴露模块接口,module 提供当前模块的一些参数。支持浏览器和 Node.js

define('myModule', function(require, exports, module) {
  var a = require('moduleA')    // 同步加载
  var b = require.async('moduleB')    // 异步加载
  exports.func = function() { ... }
  exports.pa = a.xxx
  exports.pb = b.xxx
})
  • CommonJS

专注于 Node.js 服务端的模块管理规范。在模块中 exports 对象用于导出变量或函数。

var a = require('moduleA')
exports.func = function() { ... }
exports.pa = a.xxx
  • 通用模块定义(UMD)

先判断是否支持 AMD,在判断是否支持 Node.js,否则公开到全局。

  • import/export

import 静态加载模块,export 可以指定导出模块的某个变量或函数

双向数据绑定

数据绑定是 Model 层与 View 层的映射关系。

AngularJS

  • 数据 => 视图

通过 “脏值检测” 机制,“脏” 数据指的是被修改过的数据。

实现:给每个视图模型 $scope 对象创建一个 $watchers 属性,该属性的值为数组,用来存储待检测对象。对象中包括回调函数、需要检测的值、上次更新的值等。这样每次执行检测的时候只要对数组进行遍历,然后比较数据的变化,如果发生变化则调用回调函数。

  • 视图 => 数据

(从使用上来看直接用的指令)事件绑定,加一些细节操作

VueJS

  • 数据 => 视图

Object.defineProperty 监听数据的修改,当数据变动时调用 set 函数进行操作。

  • 视图 => 数据

(从使用上来看直接用的指令)同样是事件监听,根据事件调用回调函数触发视图更新。

单向数据流

数据流是指组件之间的数据流动。

ReactJS

  • 数据 => 视图

通过 React 组件中的 state 变量和 setState 函数控制,将需要渲染的数据赋值到 state 变量上,然后通过 setState 函数更新 state 并同事渲染视图。

  • 视图 => 数据

(它们用框架的指令,咱们自己写原生代码)事件监听,调用 setState 来更新视图。

路由

网络把信息源传到目的地址的过程,通常时服务端关注的内容。但前端单页面应用框架出现后,部分路由开始由前端来控制。

  • hash

特点:①锚点 # 改变不会引起页面刷新;②hashchange 事件可以监听锚点变化。

  • history

history 是可以访问浏览器中用来记录 URL 变化的历史堆栈的全局对象,可以通过它来操作浏览器的前进和后退。

特点:①history.pushState 和 history.replaceState 修改 URL 不会引起页面刷新;②popstate 事件能监听 history 的前进后退跳转函数

Cookie 和 token

根本区别:
基于 token 认证的服务器会把登陆状态信息编码后回传给浏览器;
基于 Cookie 认证的状态信息还是保存在服务器端的会话中,同时客户端 Cookie 会存储一个与 session 对应的 id。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值