@duanyubin
2016-05-17T01:59:55.000000Z
字数 4359
阅读 412
目的: 提高性能,减少render方法执行次数
使用: 在全局store(state collection)中使用Immutable实例,component之前传递的pros也是Immutable实例。why?
如果component之前传递的是普通的object,PureRenderMixin无法达到预期的效果
const INITIAL_STATE = fromJS({
barrage: {
list: [],
connected: true
},
anchor: {},
video: {},
hot: {
list: [],
loading: false
},
room: { ...params }
})
// HotItem.jsx
<div className="img-wrap">
<img src={data.get('img_url')} />
<span className="status">{data.get('state') === 1 && '重播'}{data.get('state') === 2 && '直播'}</span>
<Count favourCount={data.get('like_num')} userCount={data.get('total_num')} />
</div>
如果component依赖的props为基本类型,则传递非Immutable实例
<Count favourCount={data.get('like_num')} userCount={data.get('total_num')} />
// Count.jsx
render() {
const { favourCount, userCount } = this.props
return <div className="m-count">
<span className="favourcount">{favourCount}</span>
<span className="usercount">{userCount}</span>
</div>
}
如果发现些单元测试无从下手,可能就是代码没有做到单一职责的原则
几个原则:
在小项目中,可以不对UI层写单元测试,前提是业务逻辑尽量少的存在于UI层。
比较下列两种写法
// 1
componentDidMount() {
if (this.props.a) {
ajaxCall()
} else {
fetchFromLocalStorage()
}
}
// 2
componetDidMount() {
this.props.fetch(this.props.a)
}
// actions.js
export function fetch(type) {
}
如何写:
Full-Stack Redux Tutorial
BDD开发模式,先写测试用例,再写被测函数
具体:
// 1. 安装下列包
$ npm i --savedev mocha chai chai-immutable
// 2. 增加chai对immutable的支持
// test_helper.js
import chaiImmutable from 'chai-immutable';
chai.use(chaiImmutable);
// 3. 增加npm script
// package.json
"scripts": {
...
"test": "cross-env NODE_ENV=production mocha --compilers js:babel-core/register --require ./test/test_helper.js \"./test/**/*.@(js|jsx)\"",
"test:watch": "cross-env NODE_ENV=production npm run test -- --watch --watch-extensions js,jsx"
...
}
// 4. 写测试用例
// reduce_spec.js
describe('Test reducer', () => {
it('should handle FETCH_INIT_INFO', () => {
// ...
expect(reducer(initialState, action).get('room')).to.eql(fromJS({
"domain": "localhost",
"port": 9999,
"userId": "temp3c628f37-dd30-43c8-875f-10c13c00efa8"
}))
})
})
注意要点:
1. 测试用例中,不应该copy被测函数的逻辑,而是应该直接写明期望值
2. 如果要对UI层进行测试,需要用的jsdom等模拟库
纯函数无副作用,仅仅依赖于函数的输入,并且当输入相同时输出保持一致
// 纯函数
const add10 = (a) => a + 10
// 依赖于外部变量的非纯函数
let x = 10
const addx = (a) => a + x
// 会产生副作用的非纯函数
const setx = (v) => x = v
const add1 = (a) => a + 1
const times2 = (a) => a * 2
const compose = (a, b) => (c) => a(b(c))
const add1OfTimes2 = compose(add1, times2)
add1OfTimes2(5) // => 11
list.map(inc).map(isZero) // => [true, false, false]
list.map(compose(isZero, inc)) // => [true, false, false]
一般,第二种的性能是第一种的2倍
借助函数组合,我们可以通过将多个小函数结合在一起来构建更复杂的数据变化
const formalGreeting = (name) => `Hello ${name}`
const casualGreeting = (name) => `Sup ${name}`
const male = (name) => `Mr. ${name}`
const female = (name) => `Mrs. ${name}`
const doctor = (name) => `Dr. ${name}`
const phd = (name) => `${name} PhD`
const md = (name) => `${name} M.D.`
formalGreeting(male(phd("Chet")))
const identity = (x) => x
const greet = (name, options) => {
return pipe([
// greeting
options.formal ? formalGreeting :
casualGreeting,
// prefix
options.doctor ? doctor :
options.male ? male :
options.female ? female :
identity,
// suffix
options.phd ? phd :
options.md ?md :
identity
])(name)
}
在调用一个函数的时候传入更少的参数,而这个函数会返回另外一个函数并且能够接收其他参数
具体可参考这篇文章
优点:
1. 重复利用小片段代码
2. 函数可配置
2. 只使用函数完成任务
var objects = [{ id: 1 }, { id: 2 }, { id: 3 }]
objects.map(function(o){ return o.id })
MAP over OBJECTS to get IDS
var get = curry(function(property, object){ return object[property] })
objects.map(get('id')) //= [1, 2, 3]
函数可配置
// R -> [Ramda](http://ramdajs.com/0.21.0/index.html)
const add = R.curry((a, b) => a + b)
add(1, 2) // => 3
const add1 = add(1)
add1(2) // => 3
add1(10) // => 11
大多数程序中,比较变量是否相等是比较变量的引用所指向的内存地址
{} == {} // false
[] == [] // false
[1,2] == [1,2] // false
但是,在数学概念上,上述三者是相等的,所以在程序中,如果要判断这种相等,就需要深比较,但是存在性能问题。
为了保证纯函数的特性,不能够在没有改变引用的情况下来改变一个变量,但是每次都要深层拷贝赋值,又会造成性能上的损失,所以,需要依靠结构共享,Persistent data structure(持久化数据结构),常见的例子是链表:
1. 比较两个链表时先比较尾部引用,如果相同,则两链表也相等,反之,需要遍历两个链表;
2. 添加某个值时,不需要复制整个表到内存中,而只是增加一个链接,然后记录这个引用O(1);
对这些不可以变数据结构进行计算得到相应hash值,每次比较只需要先比较引用,再比较此值,就能得到两个数据结构是否是值相等,这就是Immutable.js主要做的。 (Hash array mapped trie)[https://en.wikipedia.org/wiki/Hash_array_mapped_trie]
// 一般的计算方式,从内到外
square(3 + 4)
square(7) // 计算最内层的表达式
7 * 7
49
// 从外到内的计算方式
square(3 + 4)
(3 + 4) * (3 + 4) // 计算最外层的表达式
7 * (3 + 4)
7 * 7
49
// 优化
square(3 + 4)
(3 + 4) * (3 + 4) // 计算最外面的表达式
7 * 7 // 由于引用共享的存在,计算此时减少了一步
49
Lazy.js
在 ES2015 中,确实为此实现了一个标准,并且称为函数 generator
const results = _.chain(people)
.pluck('lastName')
.filter((name) => name.startsWith('Smith'))
.take(5)
.value()
一般做法:完成这件事最原始的方式就是将所有的名字拣出来,过滤整个数组,然后使用前 5 个。这就是 Underscore.js 以及绝大多数类库的做法。
使用 generator: 我们可以使用延迟计算 每次仅计算一个值,直到我们拿到了以 『Smith』开头的名字
上述代码,虽然最终是需要前五个take(5)
,但是在lodash里,要遍历5次。如果惰性求值,只需要遍历一次