解析过程

1、DNS解析
2、TCP连接
3、发起http请求
4、服务器处理http请求
5、服务器响应http请求
6、浏览器渲染页面
7、连接结束

DNS解析

  输入网址,浏览器并不知道要去哪里找资源,需要DNS递归查询对应IP

  1. DNS递归查询首先是在本地服务器进行查询,本地服务器找不到后再向根域名服务器查询,根域名服务器找不到再向上一级顶级com域名服务器查找。直到最终找到并返回IP,然后本地域名服务器会将该ip缓存起来,供下次使用。比如输入www.google.com,那么查询过程为.->.com->google.com->www.google.com
  2. 此处优化方法:
    DNS缓存:浏览器、系统(host文件)、路由器、ISP DNS缓存(互联网提供商)、本地域名服务器等都有缓存
    DNS负载均衡:根据地理位置、服务器负载量等来选择最合适的一个服务器来进行查询

TCP连接:三次握手,四次挥手

TCP报文结构:

阅读全文 »

  前端内容繁复,平时难免会碰到一些奇奇怪怪或者暂时无法理解的问题,所以特开此文将这些问题记录下来。

屏幕适配问题

  问题描述:移动端的屏幕适配问题,至今没有想明白是什么原因

  出现场景:移动端App webview内。

  复现步骤:刚开始手机字体大小为正常,打开页面后将App切后台,调整手机字体大小到最大,即出现这种情况。理论上webview内部不应该受到系统字体的影响,在原生中将该功能禁用即可。但是奇怪的是根元素的字体大小确实设置为18px,最终计算出来的字体大小却是27px。

html中已经禁止了页面缩放,但是并没有效果。

1
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width" />

scale

  解决方案:计算最后放大了多少倍,同比缩小:

阅读全文 »

  为了提高代码设计水平,测试是必不可少的。jest是facebook出的一个测试框架,里面自带断言库,而且VUE有个Vue Test Utils提供了官方支持,因此这里使用jest构建VUE单元测试部分。开始前建议先浏览一下官方网站,进行初步了解。

起步

安装&简易demo

新建一个文件夹,然后执行:

1
2
npm init
npm install jest -g

这就安装好了,接下来写一个简单的函数:

jestSimpleDemo

然后在你的项目文件夹下执行jest, 就会自动搜索所有.test.js和.spec.js文件进行测试。

增加配置

接着我们改一下目录,增加一个SRC文件夹,里面放着我们的原文件,然后新建test文件夹,将测试文件全部放进去
jestES6Demo
在demo.test.js中添加代码:

1
2
3
4
5
6
7
8
// demo.test.js
import checkNumber from '../src/demo/demo';

describe('decribe用来生成一个组', () => {
test('checkNumber', ()=> {
expect(checkNumber(2, 3)).toBe(5);
});
});
阅读全文 »

  前端适配是个麻烦事。PC端要适配不同浏览器,移动端又要适配各种屏幕。而这一切的根源,要从「设备像素」和「逻辑像素」这对概念说起。

基础概念

  设备像素(Device Pixel)是屏幕的物理像素,一块屏幕出厂时就固定的发光点数量。比如 iPhone 8 是 750 × 1334 像素,这是硬件决定的,改不了。

  逻辑像素(CSS Pixel / Logical Pixel)是我们写代码时用的像素。CSS 里的 width: 375px 指的就是逻辑像素。

  为什么会有两套像素系统?因为手机屏幕太小了,如果 1px CSS 对应 1 个物理像素,文字和按钮会小到看不清。所以苹果在 iPhone 4 上提出了 Retina 概念,用一个逻辑像素对应多个物理像素。

DPR(Device Pixel Ratio)

  DPR 就是设备像素与逻辑像素的比值:

1
DPR = 设备像素 / 逻辑像素

  常见的 DPR 值:

设备 逻辑分辨率 物理分辨率 DPR
iPhone SE / 6/7/8 375 × 667 750 × 1334 2
iPhone 12 Pro 390 × 844 1170 × 2532 3
MacBook Pro Retina 1440 × 900 2880 × 1800 2
普通 1080p 显示器 1920 × 1080 1920 × 1080 1

  DPR = 1 时,一个 CSS 像素就是一个物理像素;DPR = 2 时,一个 CSS 像素由 2×2 个物理像素渲染,所以画面更细腻。

由 DPR 引发的问题

1. 1px 边框变粗

阅读全文 »

异步编程是JS中必备的一部分。由于JS是单线程,如果全部事件都顺序执行会阻塞进程。所以一些耗时较长的事件采用异步方式进行。这里记录一些《深入浅出Node.js》笔记,有些地方没有碰到过,不理解,后续完善。

异步编程的一些问题:

  1. 异常处理
    一般,使用try/catch/finally来进行错误处理
1
2
3
4
5
6
7
try {
JSON.parse(json);
} catch (e) {
console.error(e);
} finally { // 无论是否发生错误,finally都会执行。错误会在最近的catch块中捕获,然后终止
console.log("finally");
}

现在有一个异步方法:

1
2
3
4
5
6
7
8
const async = function (callback) {
process.nextTick(callback);
}
try {
async(callback);
} catch (e) {
console.error(e);
}

这里调用async()方法只能捕获async方法的异常,但是回调callback的异常却无法捕获

阅读全文 »

多线程语言容易发生的一个问题是线程之间状态不同步。比如有两个线程A和B,A线程要对一个资源进行删除操作,B线程要对一个资源进行修改操作,这时候两个线程容易发生冲突。JS是单线程语言,貌似不会发送这种情况,但是真的如此吗?请看下面这个情况,这是在处理公司业务时碰到的,具体代码无法透漏:
lock
本地状态需要跟服务器状态同步,并且采取轮询策略。同时本地又是可以一直操作的,所以如果网络延迟就会产生图中的情况,本地数据会一直跳变。
这时可以借用多线程之间互斥锁的思想,将过程简化如下:
lock
简化之后,就发现本地操作和服务端操作两个线程要对UI这个资源同时进行操作,所以需要加个互斥锁,本地操作时禁止服务端进行操作,本地操作完成并且收到服务端的回调才解锁。

总结:多线程事件如框架组件内部数据更新、git协作开发等合作事件,最重要的是找出共享资源,理清楚操作方和他们之间的关系,再进行工作协调,保证每次只有一方在操作共享资源,保证所有状态同步。

二叉树是最常见的数据结构之一,很多复杂问题(二叉搜索树、堆、Trie)都是在二叉树基础上扩展的。本文总结二叉树的核心操作和常见题型。

二叉树的遍历

  遍历是二叉树最基本的操作,分为深度优先(DFS)和广度优先(BFS)两大类。

前序遍历(Preorder):根 → 左 → 右

1
2
3
4
function preorder(root) {
if (!root) return [];
return [root.val, ...preorder(root.left), ...preorder(root.right)];
}

中序遍历(Inorder):左 → 根 → 右

1
2
3
4
function inorder(root) {
if (!root) return [];
return [...inorder(root.left), root.val, ...inorder(root.right)];
}
阅读全文 »

动态规划(Dynamic Programming,DP)与递归常常可以一起使用。核心思想是:将大问题拆成小问题,先解决小问题,再根据小问题的解推导出大问题的解。关键是要找到状态定义和状态转移方程。

递归

  递归是 DP 的基础——一个问题可以拆成若干个结构相同的子问题。比如爬楼梯:到第 n 级台阶,要么从 n-1 跨一步上来,要么从 n-2 跨两步上来。所以:

1
f(n) = f(n-1) + f(n-2)
阅读全文 »

《JS高级程序设计》中说JS的继承有原型链、构造函数、组合式、原型式、寄生式、寄生组合式继承,加上ES6的class继承,一共有7种方式。前6种最关键的是搞清楚构造函数、原型对象、原型链的关系,其他模式都是这些的组合。

构造函数

构造函数也是函数,跟普通函数的没什么区别,但是可以用new()方法创建实例

e.g.

1
2
3
4
5
function Animal(name, legCount) {
this.name = name;
this.legCount = legCount;
}
const cat = new Animal('Tom', 4);

原型对象

每个函数都有一个prototype属性(对象没有这个属性),指向一个原型对象,即Animal.prototype( 这玩意是个对象,名字就叫Animal.prototye )

Animal.prototype默认有个constructor属性,这个对象的constructor属性指向该对象对应的构造函数,即Animal()。

1
2
3
4
5
6
console.log(Animal.prototype);
// 结果:
{
constructor: ƒ Animal(name ,leg),
__proto__: Object
}
阅读全文 »
0%