缘来我们在这里

乱世天狼的博客


  • 首页

  • 归档

接口规范初探

发表于 2018-07-03

缘起

在前后端对接的过程中,如果接口返回数据类型不稳定,经常会导致前端需要各种兼容,极易出现错误。鉴于此,这里探讨一下更合理的接口,方便前后端协作,减少bug,提升开发速度

甚至之后可以进一步的拓展为自动化生成接口调用

规范建议(根据实践,可增删)

  • 数字类型:如果为空返回0
  • object类型:如果为空返回null
  • 字符串类型:如果为空返回‘’
  • array类型:如果为空返回[]
  • object.object类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//例如:
{
test: {
name: 'test';
num: 1
}
}
//如果name,num为空

//应该返回
{
test: {
name: '';
num: 0
}
}

//不应该返回

{
test: null
}

参考资料

https://legacy.gitbook.com/book/geemus/http-api-design/details
http://jsonapi.org/

ES7 decorator

发表于 2018-06-21

前情概要

复习对象属性

一、 数据属性

  • [[Configurable]]: 表示能否通过 delete 删除属性从而  重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。直接定义的属性的这个特性默认为 true
  • [[Enumerable]]: 表示能否通过 for-in 循环返回属性。 直接定义的属性的这个特性默认为 true
  • [[Writable]]: 表示能否修改属性的值。直接定义的属性的这个特性默认为 true
  • [[Value]]: 包含这个属性的数据值。读取属性值的时候,从这个属性读;写入属性值的时候把新值保存在这个位置

要修改属性的默认特性,必须使用 es5 的 Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。

1
2
3
4
5
6
7
8
var person = {}
Object.defineProperty(person, 'name', {
writable: false,
value: "nicolas"
})
console.log(person.name)
person.name = 'Greg'
console.log(person.name)

二、 访问器属性

  • [[Configurable]]: 表示能否通过 delete 删除属性从而  重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。直接定义的属性的这个特性默认为 true
  • [[Enumerable]]: 表示能否通过 for-in 循环返回属性。 直接定义的属性的这个特性默认为 true
  • [[get]]: 在读取属性的时候调用的函数,默认值为 undefined
  • [[set]]: 在写入属性的时候调用的函数,默认值为 undefined

访问器属性设置一个值,会导致其他值的变化。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var book = {
_year: 2004,
edition: 1
}
Object.defineProperty(book, "year", {
get: function(){
return this._year
},
set: function(newValue){
if(newValue > 2004){
this._year = newValue
this.edition += newValue - 2004
}
}
})
book.year = 2005;
console.log(book.edition)

设置多个对象可以用 Object.defineProperties

 注意 Object.defineProperties 和 Object.defineProperty 设置的属性的 Configurable 特性为 false

三、 读取属性的特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var book = {}

Object.defineProperties(book, {
_year: {
value: 2004
},
edition: {
value: 1
},
year: {
get: function() {
return this._year
},

set: function(){
if(newValue > 2004){
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
})

var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
console.log(descriptor.value)
console.log(descriptor.configurable)
console.log(descriptor.get)
var descriptor2 = Object.getOwnPropertyDescriptor(book, "year");
console.log(descriptor.value)
console.log(descriptor.configurable)
console.log(descriptor.get)

复习高阶函数

在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:

  • 接受一个或多个函数作为输入
  • 输出一个函数

let’s begin ES7 decorator

一、再铺垫一层,class 究竟是什么

es6 class

1
2
3
4
5
6
7
8
9
10
11
12
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}

toString() {
return "(" + this.x + ", " + this.y + ")";
}
}
let p = new Point(1, 2);

对应 es5

1
2
3
4
5
6
7
8
9
10
function Point(x, y) {
this.x = x;
this.y = y;
}

Point.prototype.toString = function() {
return "(" + this.x + ", " + this.y + ")";
};

var p = new Point(1, 2);

结论:es6class 是 es5 构造函数的语法糖

二、方法或属性上面的装饰,属性 decorator

栗子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 注意这里的 `target` 是 `Dog.prototype`
function readonly(target, key, descriptor) {
descriptor.writable = false;
return descriptor;
}
class Dog {
@readonly
bark() {
return "wang!wang!";
}
}

let dog = new Dog();
dog.bark = "bark!bark!"; // 不起作用

结论:方法或属性上面的装饰其实就是接收 target,key,旧的 descriptor,然后返回新的 descriptor 给 Object.defineProperty 使用(到前面看 Object.defineProperty)

三、类本身的装饰,类装饰

栗子

1
2
3
4
5
6
7
8
9
10
function doge(isDoge) {
return function(target) {
target.isDoge = isDoge;
};
}

@doge(true)
class Dog {}

console.log(Dog.isDoge);

结论:类本身的装饰可以等价于一个高阶函数,接受类(构造函数),然后返回一个装饰过的新类

总结

装饰器真的非常简单,技术没有魔法,基础都是非常非常简单的概念。

属性装饰的再思考: 观察属性装饰接受的参数,target,key,descriptor。其实也还是一个高阶函数,只不过接收了 target,key,指明了具体修饰的内容,相当于类装饰的一个子概念。

再抽象: 本篇所述的所有东西无非是 高阶函数概念的扩展。高阶函数本身也很简单:1.接受一个或多个函数作为输入 2.输出一个函数。

再再抽象: 语言本身的概念其实不多,很多东西都是一个概念的衍生而已,原生概念类似于内力,各种衍生类似于招数。内力是基础,招数是运用。

参考

  • ECMAScript 6 入门之 class
  • Exploring EcmaScript Decorators
  • 高阶函数-维基百科

学习mobx

发表于 2018-05-29

资源

  • mobx 文档
  • mobx 10 分钟简介
  • Practical React with MobX

Core MobX API

  • observable
  • computed
  • reactions
  • transaction
  • actions

es6拾遗

发表于 2018-05-29

super 关键字

super 这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。

super 虽然代表了父类 A 的构造函数,但是返回的是子类 B 的实例,即 super 内部的 this 指的是 B,因此 super()在这里相当于 A.prototype.constructor.call(this)。

1
2
3
4
5
6
7
8
9
10
11
12
13
class A {
constructor() {
console.log(new.target.name);
}
}

class B extends A {
constructor() {
super();
}
}
new A(); //A
new B(); //B

第二种情况,super 作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

加上 static 关键字的方法表示不会被实例继承,而是直接通过类来调用

js高程拾遗

发表于 2018-05-28

typeof 操作符

  • undefined
  • boolean
  • string
  • number
  • object
  • function

五种基本类型

  • Undefined
  • Null
  • Boolean
  • Number
  • String

引用类型

  • Object
  • Array
  • Date
  • RegExp
  • Function
  • 基本包装类型(Boolean Number String)

函数实际上是对象,每个函数都是 Function 类型的实例,而且都与其他引用类型一样具有属性和方法。函数名实际上也是一个指向函数对象的指针。

面向对象

每个对象都是基于一个引用类型创建的

属性类型

一、 数据属性

  • [[Configurable]]: 表示能否通过 delete 删除属性从而  重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。直接定义的属性的这个特性默认为 true
  • [[Enumerable]]: 表示能否通过 for-in 循环返回属性。 直接定义的属性的这个特性默认为 true
  • [[Writable]]: 表示能否修改属性的值。直接定义的属性的这个特性默认为 true
  • [[Value]]: 包含这个属性的数据值。读取属性值的时候,从这个属性读;写入属性值的时候把新值保存在这个位置

要修改属性的默认特性,必须使用 es5 的 Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。

1
2
3
4
5
6
7
8
var person = {}
Object.defineProperty(person, 'name', {
writable: false,
value: "nicolas"
})
console.log(person.name)
person.name = 'Greg'
console.log(person.name)

二、 访问器属性

  • [[Configurable]]: 表示能否通过 delete 删除属性从而  重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。直接定义的属性的这个特性默认为 true
  • [[Enumerable]]: 表示能否通过 for-in 循环返回属性。 直接定义的属性的这个特性默认为 true
  • [[get]]: 在读取属性的时候调用的函数,默认值为 undefined
  • [[set]]: 在写入属性的时候调用的函数,默认值为 undefined

访问器属性设置一个值,会导致其他值的变化。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var book = {
_year: 2004,
edition: 1
}
Object.defineProperty(book, "year", {
get: function(){
return this._year
},
set: function(newValue){
if(newValue > 2004){
this._year = newValue
this.edition += newValue - 2004
}
}
})
book.year = 2005;
console.log(book.edition)

设置多个对象可以用 Object.defineProperties

 注意 Object.defineProperties 和 Object.defineProperty 设置的属性的 Configurable 特性为 false

三、 读取属性的特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var book = {}

Object.defineProperties(book, {
_year: {
value: 2004
},
edition: {
value: 1
},
year: {
get: function() {
return this._year
},

set: function(){
if(newValue > 2004){
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
})

var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
console.log(descriptor.value)
console.log(descriptor.configurable)
console.log(descriptor.get)
var descriptor2 = Object.getOwnPropertyDescriptor(book, "year");
console.log(descriptor.value)
console.log(descriptor.configurable)
console.log(descriptor.get)

创建对象

  • 工厂模式
  • 构造函数模式
  • 原型模式
  • 动态原型模式(通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型)
  • 寄生构造函数模式
  • 稳妥构造函数模式

金字塔原理 - 思考、表达和解决问题的逻辑

发表于 2018-05-25

第一篇:表达的逻辑

金字塔重的思想以三种方式互相关联 —— 向上、向下和横向。位于一组思想的上一个层次的思想是对这一组思想的概括,这一组思想则是对其上一层次思想的解释和支持。

文章中的思想必须符合以下原则:

  1. 纵向:文章中任一层次的思想必须是其下一层次思想的概括。
  2. 横向:每组中的思想必须属于统一逻辑范畴
  3. 横向:每组中的思想必须按逻辑顺序组织

组织思想基本上只可能有四种逻辑顺序:

  • 演绎顺序:大前提、小前提、结论
  • 时间(步骤)顺序:第一、第二、第三
  • 结构(空间)顺序:波士顿、纽约、伦敦
  • 程度(重要性)顺序:最重要、次重要、等等

你选择的逻辑顺序展现了你在组织思想时的分析过程。如果思想的组织方式是演绎推理,那么这些思想的逻辑顺序就是演绎顺序;如果思想按照因果关系组织,那么其逻辑顺序就是时间顺序;如果是对某种现有结构进行评论,那么其逻辑顺序就是结构顺序;如果按类别组织思想,那么其逻辑顺序就是程度顺序(重要性顺序)。因为演绎推理,发现因果关系,化整为零,和归纳总结是大脑可进行的仅有的4种分析活动,这4种顺序也是大脑可用于组织思想仅有的4种顺序。

不要幻想一坐下来就开始将思想组织称金字塔。首先你必须梳理你想要表达的思想。

人一般不会阅读自己已经了解了的内容,因此,也可以说,表达思想的主要目的就是向受众传递新的信息。

金字塔巨大的结构价值就在于它迫使你在理清思路时,从视觉上使纵向的疑问/回答式对话关系清晰化。你的每一个表述都应当引发读者的疑问,而你也必须在这一表述下的横向结构层次上逐个回答读者的疑问。

自上而下法构建金字塔

  1. 画出主题方框

这个方框就是你文章的金字塔结构最顶部的方框。在方框中填入你要讨论的主题,当然前提是你知道要讨论什么主题,否则请跳到步骤2

  1. 设想主要疑问

确定文章的读者。你的文章将面对哪些对象?你希望文章能回答读者头脑中关于该主题的哪些疑问?如果你能确定读者的主要疑问,请写出来,否则跳到步骤4

  1. 写出对该疑问的回答

如果你还不清楚答案,请注明你有能力回答该疑问。

  1. 说明‘背景’

你需要证明,现阶段你能清晰论述的主要的疑问和答案。具体做法是:把要讨论的主题与背景结合,作出关于该主题第一个不会引起争议的表述。首先,关于该主题的哪些表述肯定不会引起读者的疑问呢?(因为读者知道这一表述,或者根据以往经验很容易判断该表述的正确性)。

  1. 指出冲突

现在你已经开始与读者进行疑问/回答式的对话了。想象一下,读者表示同意,点着头说:“对,我知道这个情况,有什么问题么?”此时,你就应当考虑“背景“中发生了哪些能使读者产生疑问的冲突,例如发生了某种意外,出现了某个问题,或出现了明显的不应当出现的变化。”背景“中发生了哪些”冲突“,以致引发了读者的”疑问“呢?

  1. 检查“主要疑问”和“答案”

对“背景”中“冲突”的介绍,应当直接导致读者提出主要疑问(已在步骤2中列出)。否则,应重新介绍“背景”中的“冲突”,使之可以直接导致读者提出主要疑问。可能有时“背景”中的“冲突”与主要疑问对不上号,这就需要你重新构思。

进行以上步骤的目的,是确保你了解自己将要回答哪些疑问。一旦确定了主要“疑问”,其他要素都很容易在金字塔结构中各就各位。

初学者注意事项

  1. 一定要先搭结构,先尝试自上而下法

一旦你着手将思想变成文字,它就似乎戴上了最美丽的光环,令你感觉‘字字珠玑’,甚至不愿意进行必要的修改。因此,不要试图一下子就把整篇文章都写出来,因为你稍后就可能很容易地想出文章的结构。一旦你的思想变成了文字,你就可能会觉得写得不错,而根本不管你的思路实际上是不连贯的。

  1. 序言先写背景,将背景作为序言的起点

一定要从‘背景’开始构思,因为按照这个顺序,你更容易准确地找到‘冲突’和‘疑问’。

  1. 先多花时间思考序言,不要省略

先想好序言,避免开始论证时还在想背景或冲突。当你坐下来开始写作时,经常头脑中已经有了一个完整的主要思想。这样,触发思想的‘疑问’也很明显。这是,你就很容易直接跳到关键句层次,开始回答由主要思想引起的新的疑问。我劝你不要这么做,多数情况下,你会发现自己还在思考和组织属于‘背景’或‘冲突’的信息。这样会使你陷入复杂、混乱的论证中。你应当先整理出序言的信息,然后把注意力完全集中在金字塔结构中较低层次的思想上。

  1. 将历史背景放在序言中

不应该在文章的正文部分才告诉作者过去发生的事情。

  1. 序言仅涉及读者不会对其真实性提出质疑的内容

因为这样可能导致读者提出非你所愿的‘疑问’。

  1. 在关键句层次上,更宜选择归纳推理法而非演绎论证法

归纳推理比演绎推理更容易理解

演绎推理和归纳推理

演绎推理需要注意:1. 演绎推理的过程不要超过4个步骤;2. 推导出来的结论不要超过两个

第二篇:思考的逻辑

通常情况下,你可以很快确定文章的主题和读者可能提出的疑问,想好(序言,开场白,引言)中的“背景”和“冲突”,提出文章的中心思想和关键句要点。然后,你就可以使用疑问/回答式的对话方式,在每一个关键句要点之下的层次上展开论述说明。

当你对文章结构的思考已深入到关键句层次的下一个层次时,你就应开始写作了。更低层次的思想不要在构思阶段完成,而应放在实际的写作过程中完成。当你写完全篇时,还必须仔细检查一下全文的结构,因为你可能发现自己犯了以下两种常见错误之一:

  • 仅仅因为可以用一个名词概括,而将关联性很小的思想排列在一起(如‘10个步骤’或‘5个问题’等),实际上这些思想之间不存在逻辑关系。
  • 金字塔结构顶端的中心思想,使用的是‘缺乏思想’的橘子(如‘该公司存在5个问题’),而非具有揭示性的观点。

大脑的归纳分组分析活动只有以下三种

  • 时间(步骤)顺序
  • 结构(空间)顺序
  • 程度(重要性)顺序
  1. 确认前因后果关系

当你在文章中告诉读者采取某种行动时(如:辞退销售经理,将盈利指标分解到各个销售分区),你必定认为通过这种行动会产生某种预想特定效果。你首先要确定希望取得的结果或效果,然后指出为取得这一效果必须采取的行动。

当必须采取多种行动(如:解决问题的三个步骤),以取得该结果时,这些行动就构成了一个过程、流程或一个系统,即共同产生某结果的原因的集合。完成该过程或系统需采取的行动只能按时间顺序依次进行。因此,代表一个过程或系统的一组行为,必定是按时间顺序排列,而对该组行为的概括,必定是采取这些行为要取得的结果或达到的目标。

  1. 将整体分割为部分,或将部分组成整体

在绘制组织结构图或行为结果图时,通常需要将整体分割为部分,或将部分组成整体。例如,如果你需要找出“在行业成功的关键因素”,首先你必须画出该行业的结构图,然后确定在各个部分成功的必须要素。这些必需要素之间的逻辑关系,与此前画出的行业结构图各个部分之间的关系互相一一对应,这种逻辑顺序就是结构顺序。

  1. 将类似事务按重要性归为一组

按照“重要性”或“程度”从高到低,即从重要到次重要,或从大至小的顺序排列,这就是程度顺序,也称之为比较顺序或重要性顺序。

以上3种逻辑顺序既可以单独使用,也可以结合使用,但是每一组思想中都必须至少存在一种逻辑顺序。因此在写作时,你必须有意检查每一组思想中是否存在某种逻辑顺序。如果该组思想不存在任何一种逻辑顺序,那么显然这一分组有问题,你应该用逻辑分析框架的知识找出问题所在。

下一步介绍逻辑顺序的知识,以及如何运用这些知识检查你的思路。

时间顺序

  • 根据结果寻找原因
  • 揭示隐含的逻辑思路

提示,时间顺序:在按照时间顺序组织的思想中,你要按照采取行动的顺序(第一步,第二步,第三步)依次表述达到某一结果必须采取的行动。

结构顺序

创建逻辑结构

在将某个整体(不论是客观存在的还是概念性的整体)划分为不同的部分时,你必须保证划分后的各部分符合以下要求:

  • 各部分之间相互独立(mutually exclusive),没有重叠,有排他性。
  • 所有部分完全穷尽(collectively exhaustive),没有遗漏。

通常有三种划分组织活动的方式:根据活动本身(如:研发,生产,市场,营销);根据活动发生的地点(如:国家东部,国家中西部,国家西部);根据针对特定产品、市场或客户活动的集合(如:各事业部,各业务单元,轮胎部,硬件部,体育设备部)。

  • 如果划分时强调活动本身,那么各部分展现的是一个逻辑过程(流程),因此应该采用时间顺序。
  • 如果划分时强调地点,那么各部分呈现的是地理状况,应采用结构顺序。
  • 如果划分时强调与某一产品或市场有关的活动,那么划分就是一种归类。各部分思想应采用重要性顺序,判断重要性的标准可以是任何排序标准(如销量、投资额等。)

描述逻辑结构

自上而下,自左而右

修改逻辑结构

用结构顺序概念检查思路

程度顺序

程度顺序也成重要性顺序。是你对一组因为具有某种共同特点而被聚集在一起的事务所采用的顺序,如:3个问题,4个原因,5个因素。表达者将思想简单罗列出来而缺乏深入思考的现象尤为严重。

先重要后次要,先强后弱。

概括各组思想

确保思想属于同一组,应抽象,提炼,概括思想精华。

总结句避免使用缺乏思想的句子

如果已经得出了一个概括性思想,你就可以在该思想的基础上用以下两种方式延续你的思路:

  • 对其作进一步评论(演绎法)
  • 找出类似的思想(归纳法)

前提是原有的概括思想是根据一个适当的思想组概括出来的

如何进行正确的概括?首先检查该组思想的分组基础,保证其相互独立,完全穷尽。然后,你需要确定准备得出的概括性思想的语句类型。

思想的表达方式可以是行动性语句,告诉读者做什么事;也可以是描述性语句,告诉读者某些事的情况。

  • 概括行动性思想(介绍采取的行动,行为,动作,步骤,流程)时,应说明采取行动后取得的美国(效果,达到的目标)。
  • 概括描述性思想(介绍背景,信息)时,应说明这些思想具有的共同点的含义(共同点的意义)。

5月任务总结

发表于 2018-05-25

业务层面

本月 200w 预计可稳定完成,下月+100w 目标,如无意外应该可稳定完成。数据:
5月kpi及完成程度

技术层面

已经做的

  • 代码规范的限制
  • 编译框架和 webpack 持续缓存已经加了上去
  • promise 和 base 已经在推广和使用
  • mobx(严格模式)已经在重构项目中使用

mobx 相对来说更容易被初入手的人接受,redux 对于很多人不好理解,我之前做的 redux 入驻部分在我不负责这一块的时候就被破坏的不成样子。而且现在采用多页面模式(兼容 c 端 app 回退机制),更适合分开维护状态的 mobx。

待完成的

  • 针对 c 端 app 的体验优化,页面 title 维护,回退的状态刷新等
  • 针对 b 端 app 的优化,首先是重构 vue 代码,然后才谈的上优化,:),然后是 b 端关于入驻,修改密码等设计到我们这边业务的页面全部远端化,目前还有部分非远端页面,维护麻烦。
  • 性能监控的完整体系,移动端追求的是极致的加载速度,因而需要统计各个页面的加载性能,并对应做优化
  • 报错的监控,目前 onerror 的统计被 mms 覆盖,看不到,很心塞
  • base 的加强和优化,base 拍照 api 的问题在于内部从拿到图片到处理结束这一段时间没有暴露给外部,所以造成用户等待拍照 api 处理事件过长,2s 左右。base 分享 api 不够细致,只有 hideqq 的选项,更合理的应该是可以传入参数控制分享内容,并且缺少控制分享选项的控制。关于 app 的部分 base api 还不完整,而且重复用了并不需要引入的 pinbridge
  • 去掉 jquey,vondor 依赖分析,jquery 和 react-dom 两个占比最大,均在 28%左右,大小在 200k 上下。reack-dom 如果要减小,可以考虑使用 preact,但是怕有风险,需要评估。jquery 是一定要去掉的,根本没有必要,当初加进去估计是有人图方便,但是现在用的地方太多,不太好一下干掉。
  • 旧代码的改造,入驻这一整块现在整体比较乱,换了几波人接手,所以我计划下个月将入驻这一块整体迁移到现有编译框架下面,去掉 redux,react-router 等,毕竟多页面和 mobx 不需要两者。还有 assets 下面的旧页面,还是最原始的 jquey,但是改动频度相对较小,可以排在入驻改造之后。
  • 良好的测试体系,手写测试数据是很蛋疼还无效(或者说低效)的事情,测一个已经知道的结果完全没有必要。如何完美的 mock 数据,并优雅切入是一件需要迫切解决的事情。ui 测试在看katalon
  • 最佳实践,这个一直在追求,理想状态是从开发到测试到性能分析一整套完善的流程,形成一个最佳实践,然后不断更新最佳实践,让所有人有参照的写代码

happypack应用

发表于 2018-05-23

happypack 原理解析

传送门

pearlandjade

发表于 2018-05-09
  • 精读 js 模块化发展

  • git 快捷键

  • mac-win 虚拟机使用数字键盘

  • 玩转 webpack.DllPlugin

  • mermaid markdown 格式画流程图

  • event-loop

  • jsfiddle 前端演示工具

  • setTimeout or setInterval

  • 深入浏览器理解 CSS animations 和 transitions 的性能问题

  • 浏览器前端优化

  • 虚拟 dom 实现

  • 函数防抖与函数节流

  • webpack 配置优化

  • web performance
  • performance 统计
  • 移动端 app 版本分布统计-腾讯
  • what-happens-when
  • 白噪音
  • 如何选择开源许可证
  • 微信浏览器实现后退记忆浏览位置
  • MySQL 数据库设计总结
  • 从0开始学MySQL
  • Sortable
  • webpack 提速
  • 改善代码系列
  • 极光大数据
  • 绘图网站
  • 都江堰原理
  • MIT 开放课程
  • 面试和算法
  • 现代浏览器原理
  • THE WEB’S SCAFFOLDING TOOL FOR MODERN WEBAPPS
  • ppt背景音乐以及视频
  • 前端优质博客
  • 正则表达式验证网站1
  • 正则表达式验证网站2
  • 学习js
  • canvas库
  • front-end handbook

long-term-cache

发表于 2018-05-09

获取资源

浏览器向服务器请求资源 foo.js

服务器返回 foo.js,并设置缓存时间: cache-control: max-age=312312, public

再次请求

浏览器查询本地磁盘是否有 foo.js,并检查它是否已经过期。如果没有过期就直接返回。

Cache Busting Technique

如果缓存本地没有过期,服务端已经过期,那么后果很严重,代码更新了,然而用户用的还是本地缓存的旧代码。

  1. 修改文件的名字:foo.js -> foo.v2.js
  2. 修改文件的路径:/static/foo.js -> /static/v2/foo.js
  3. 加 query string : foo.js -> foo.js?v=qwer

一般使用第一种方法我们的理想当然是:哪个文件更新了,就自动地生成一个新的文件名。

code splitting

参考资料

用 webpack 实现持久化缓存

webpack-training-project

happypack

123…7

乱世天狼

乱世天狼 | 前端 | html | css | html5 | css3 | react | redux | webpack | 哲学 | 精神 | 生活

67 日志
48 标签
© 2020 乱世天狼
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4