@duanyubin
2016-05-17T01:59:55.000000Z
字数 4359
阅读 477
目的: 提高性能,减少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.jsxrender() {const { favourCount, userCount } = this.propsreturn <div className="m-count"><span className="favourcount">{favourCount}</span><span className="usercount">{userCount}</span></div>}
如果发现些单元测试无从下手,可能就是代码没有做到单一职责的原则
几个原则:
在小项目中,可以不对UI层写单元测试,前提是业务逻辑尽量少的存在于UI层。
比较下列两种写法
// 1componentDidMount() {if (this.props.a) {ajaxCall()} else {fetchFromLocalStorage()}}// 2componetDidMount() {this.props.fetch(this.props.a)}// actions.jsexport function fetch(type) {}
如何写:
Full-Stack Redux Tutorial
BDD开发模式,先写测试用例,再写被测函数
具体:
// 1. 安装下列包$ npm i --savedev mocha chai chai-immutable// 2. 增加chai对immutable的支持// test_helper.jsimport 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.jsdescribe('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 = 10const addx = (a) => a + x// 会产生副作用的非纯函数const setx = (v) => x = v
const add1 = (a) => a + 1const times2 = (a) => a * 2const 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) => xconst greet = (name, options) => {return pipe([// greetingoptions.formal ? formalGreeting :casualGreeting,// prefixoptions.doctor ? doctor :options.male ? male :options.female ? female :identity,// suffixoptions.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) // => 3const add1 = add(1)add1(2) // => 3add1(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 * 749// 从外到内的计算方式square(3 + 4)(3 + 4) * (3 + 4) // 计算最外层的表达式7 * (3 + 4)7 * 749// 优化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次。如果惰性求值,只需要遍历一次