本文主要探讨,如何避免内存泄漏,以及内存泄漏的发现与分析。
ES6语法:apply、call、compose函数、柯里化函数
参考文章
浅析 JavaScript 中的 函数 currying 柯里化
apply与call的区别
区分apply与call只有一句话
foo.call(this, arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)
call,apply都是Function.prototype(prototype
是javascript
的原型模式)的方法,是JavaScript引擎的内在实现,意味着每个Function对象实例,就是每个方法都有call,apply属性。
- 相同点:作用完全相同
- 不同点:传递参数不同,call传递参数序列,apply传递数组
this指代上下文对象,是指每个实例的this,代码在该this内执行。
当this为null时,指向全局对象,意思是调用一个函数时,不是一个具体对象的方法
arguments
使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们,意味着能以数组的形式,遍历函数的所有参数。
举个栗子
1 | componentDidMount() { |
柯里化curry
简单的说柯里化就是通过传入函数所需的部分参数,将一个函数分割为多个的一种技术。或者叫分部传参数求解。
柯里化允许你将一个函数转换为一些列函数,在经常调用一个相同参数的函数时,柯里化是很好的解决方案。
举个例子
1 | function multiplier(x, y){ |
利用闭包特性,函数会保留之前的传递的x
multiplier(3, 4) == multiplier (3)(4)
一个典型的柯里化函数
1 | componentDidMount() { |
执行reciprocal(2)
相当于执行了this.curry(divider,1)(2)
,下面来重点讲解执行过程。
this.curry
执行[].slice.call(arguments,1)
,去掉传入的第一个参数即divider函数
,返回fixedArgs
,此时
fixedArgs=[1]
- 继续执行返回匿名函数,同时传入变量2
- 执行匿名函数,
fixedArgs.concat([].slice.call(arguments))
,将现在的变量arguments和之前的变量合并,返回args - 使用apply执行第一个参数就是
divider函数
,参数是上一步拼接好的args函数 - 返回结果,完毕。
ES6语法:三个点参数
rest参数
ES6 引入 rest 参数(形式为“…变量名”)
- rest参数中的变量代表一个数组
- 函数的length属性,不包括rest参数
- rest参数后不能再有其他参数,否则报错
1 | // 报错 |
与箭头函数结合
1 | const numbers = (...nums) => nums; |
扩展运算符
1 | // ES6的写法 |
扩展运算符也可以与解构赋值结合起来,用于生成数组。
但是只能放在参数的最后一位
1 | const [first, ...rest] = [1, 2, 3, 4, 5]; |
扩展运算符内部调用的是数据结构的 Iterator 接口,因此只要具有 Iterator 接口的对象,都可以使用扩展运算符
1 | let map = new Map([ |
react-native基础:redux学习2-实战篇
导航
本篇blog是在对redux理论知识有了足够了解后,做的实战架构。
实战
安装需要用到的库
1 | npm install --save redux |
react绑定库跟开发者工具
redux
react-redux
redux-devtools
异步action构造器redux-thunk
日志工具
redux-logger
基础用法 同步的action
引入支持
1 | import { createStore } from 'redux' |
将根组件包装进<Provider>
1 | //reducer函数,所有的 |
通过 react-redux
提供的 connect()
方法将包装好的组件连接到Redux
。尽量只做一个顶层的组件,或者 route
处理
任何一个从 connect()
包装好的组件都可以得到一个 dispatch
方法作为组件的 props
,以及得到全局 state
中所需的任何内容。 connect()
的唯一参数是 selector
。
1 | const PageContainer = connect()(PageContainer); |
高价用法 异步action
如何把action creator跟网络请求结合起来呢。
redux-thunk:一个搭建异步action的构造器。
其作用就是把一些比较复杂的动作(例如这里用到的异步操作)封装到一个action中去。
通过使用指定的 middleware,action creator 除了返回 action 对象外还可以返回函数。这时,这个 action creator 就成为了 thunk。
当 action creator 返回函数时,这个函数会被 Redux Thunk middleware 执行。这个函数并不需要保持纯净;它还可以带有副作用,包括执行异步 API 请求。这个函数还可以 dispatch action,就像 dispatch 前面定义的同步 action 一样。
注意dispatch
定义:通过 store.dispatch()
将 action
传到 store
使用 ES6 计算属性语法,使用 Object.assign()
来简洁高效地更新 state
的值1
return Object.assign({}, state, newState);
注意事项
- fetch
当我们在react-native版本可以直接使用这个强大的网络操作API,当时在react-web中大多数浏览器不支持,建议使用[isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch.所以我考虑还是在web项目使用jQuery,最稳妥。
1 | // 每次使用 `fetch` 前都这样调用一下 |
react-native基础:global全局变量和持久化
如何实现react-native的全局变量呢
参考网上的答案,使用global
,类似于web的window,
比如
global.isBeat = true,
全局就知道这是一个测试版
如何做持久化存储呢
- 支持react-native(AsyncStorage,简单的异步的持久化的key-value存储系统)
- 支持浏览器(localStorage)
- es6语法,promise异步读取,使用jest进行单元测试
推荐new出来的Storage给global,这样我们就能全局使用了。
比如
1 | var storage = new Storage({ |
保存 读取 删除
1 | // 使用key来保存数据。这些数据一般是全局独有的,常常需要调用的。 |
react-native基础:redux学习1-理论篇
导航
理论
本篇blog主要讲解redux的一些理论,以及第三方的组件库和其优秀的解决思路,所谓理论现行。
我在查阅了大量参考文章和blog后,有感于大部分文章都侧重于讲某个点,而没有系统的让初学者从0开始对redux进行理解,所以写下了这篇总结。
当然我们首先还是要站在巨人的肩膀,需要预先阅读一下文档,我起初读完以下文档也是萌萌哒,直到对所有的知识串起来思考,才有恍然大悟的感觉。首先是Redux 中文文档,然后是深入到源码:解读 redux 的设计思路与用法,以及React-Native With Redux,最后如果对redux的基础知识有了初步了解,可以看下这个讨论帖这段时间研究了下Redux,写写自己对它的感觉。
Flex与Redux的关系
Redux是遵循了单向数据流Flex的设计,但是做了流程的简化。
Redux是javascript状态容器,提供可预测化的状态管理,可以构建一致化的应用,除了和React一起用外,还支持其他界面库,体积小(只有2kb)而且没有任何依赖。Redux由Flux演变而来,但是避开了Flux的复杂性,上手快,使用简单,而且社区活跃,是目前主流的Flux数据流框架(学习Redux可以参考Redux中文文档)
Redux总览
在 Redux 的[源码目录][redux-src]
src/
,我们可以看到如下文件结构:
1 | ├── utils/ |
- store: 应用中所有的
state
都以一个对象树的形式储存在一个单一的store中,state
就是每个component
里都存在的状态集合,你也可以理解为java类的属性和方法。 - action: 惟一改变 state 的办法是触发 action,一个描述发生什么的对象。它是 store 数据的唯一来源。
- reducers:为了描述 action 如何改变 state 树,你需要编写 reducers。
- compose:没有依赖,是个纯函数,实现函数的层级合并,从右开始。
- createStore:创建store的函数。参数是(reducer,初始化state,中间件),返回store
- combineReducers(reducers):可以合并不同的reducer,便于不同功能的reducer进行分支化管理
- bindActionCreators(actionCreators,dispacth):实现自动
dispatch
§ action
action本质是是一个包含type
属性的普通对象,type是它的key也是识别码。改变state必须dispatch
一个action
。
一般用法component的state其实是从props传递的,以propsMaptoState形式存储在store中。
高阶用法包括selector绑定
,这是为了解决全局变化而对store的state做了最小化拆分
- 存储最小的可能变化state
- 提高效率,除非一个参数发生改变,否则不会重新计算
- selector是可组合的,一个selector可以导出给其他
selector
使用
§ reducer
指明如何更新state
,reducer
本质是一个一function
,接收旧state
和 action
,返回新的 state
,我们叫nextState
,也就是说每次返回的都是新的state,而不是旧state的副本。reducer返回啥,state就被替换成啥。
思考:这样就能实现数据的回滚了,比如执行redo,undo操作了。
§ store
Store 就是把它们联系到一起的对象。Store 有以下职责:
- 维持应用的 state;
- 提供 getState() 方法获取 state;
- 提供 dispatch(action) 方法更新 state;
- 通过 subscribe(listener) 注册监听器。
一个Redux应用只能有一个单一的store
§ compose
主要的作用是让代码更优雅,如下:
1 | var re1 = func3(func2(func1(0))); |
§ creteStore(reducer,initalState,enhaner)
经常的用法是创建store,并给store添加中间件
1 | const finalCreateStore = Redux.compose( |
§ combineReducers(reducers)
无论应用的状态树多复杂,都可以通过逐层下分,来管理对应部分的state,如下图
1 | aReducer(a_value, action) -------------------- a_value |
无论dispatch哪个action,都会流通所有的reducer
这也是为何 reducer 必须返回其对应的 state 的原因。否则整合状态树时,该 reducer 对应的键值就是 undefined
§ bindActionCreators(actionCreators,diapatch)
把我们手动的action的dispatch过程变成了自动.
⊙ Redux 与传统后端 MVC 的对照
Redux | 传统后端 MVC |
---|---|
store |
数据库实例 |
state |
数据库中存储的数据 |
dispatch(action) |
用户发起请求 |
action: { type, payload } |
type 表示请求的 URL,payload 表示请求的数据 |
reducer |
路由 + 控制器(handler) |
reducer 中的 switch-case 分支 |
路由,根据 action.type 路由到对应的控制器 |
reducer 内部对 state 的处理 |
控制器对数据库进行增删改操作 |
reducer 返回 nextState |
将修改后的记录写回数据库 |
第三方辅助类组件库
§ redux-actions
专门为redux准备的,flux standard action的工具集。
什么是flux standard action?
简称fsa,1
2
3
4
5
6
7{
type: 'ADD_TODO',
payload: {
text: 'Do something.'
}
}
出错时1
2
3
4
5{
type: 'ADD_TODO',
payload: new Error(),
error: true
}
type必须的,payload可选的,error可选的,meta可选的
判断一个action是否是flux standard action1
2
createAction(type, payloadCreator = Identity, ?metaCreator)
- 参数type:就是
action
的type
,一般是string
, - 参数payloadCreator:就是
payload
生成器,类型只能是function
,undefined
,或者null
,
createAction
是一个Action生成器,返回一个Flux Standard Action
,这个Action
的payLoad
的值就是payloadCreator的返回值
举例:
1 | let increment = createAction('INCREMENT', amount => amount); |
好处是如果payload是一个Error对象(new TypeError
),react-actions
就能自动把Action.error = true
举例:
1 | const increment = createAction('INCREMENT'); |
createAction
也能返回它的type
,然后作为type
传参给handleAction
或者handleActions
使用
- 作为参数在
handleAction
中使用 - 作为object key 在handleActions中使用
handleAction(type, reducer | reducerMap = Identity, defaultState)
包装一个reducer,这个reducer仅能处理一个,确定type的、flux标准的action。
- 参数type:就是一个action的type
- 参数reducer:就是reducer函数,用来处理传递的action里的payload和state,然后返回新的state
- 参数defaultState,当reducer收到的参数是
undefined
时,就返回defaultState
handleActions(reducerMap, defaultState)
- 参数reduerMap:就是一个
action type
为key
,reducer
为value
的键值对。 - 参数defaultState:
把大量使用handleAction
创建的reducer
合并
§ Reselect
Reselect是一个第三方库,解决数据冗余的问题。这个问题是怎么产生的呢?
首先:原本store中的state是通过props,数据一级一级的传递,在 render 中处理,避免了状态判断的问题,即拿到的数据总是最新的,缺点就是每次重新计算。
然后:一层层传递的数据,每个层级组件都要用,一旦原始数据被污染了,需要保存多份原始数据的处理结果,数据的冗余就出现了。
解决方案:
Container component 模式很,就是每个组件connect自己所需要的数据.
reselect的三个特性
- Selectors can compute derived data, allowing Redux to store the minimal possible state.(Selectors可以计算派生数据,允许Redux存储最小可用state)
- Selectors are efficient. A selector is not recomputed unless one of its arguments change.(Selectors是高效的。除非其中一个参数发生更改,否则不会重新计算Selectors)
- Selectors are composable. They can be used as input to other selectors.(Selectors是可组合的,也可以作为input给其他Selectors使用)
React-Redux容器组件与展示组件分离的开发思想
这个在Redux 中文文档中有详细跟直观的讲解。
通俗来讲就是,一个Redux应用切成两部分来管理数据流
Container:容器组件
-在这里使用redux,控制分发需要向下传递的state,action创建函数
View:展示组件
-我们要展示数据的的view,以及触发action的操作
参考文献
react-native学习路线
react-native是Facebook推出的跨平台开发技术,使用JavaScript代码,目前是es6。主要涉及知识点flexbox(弹性工具盒)布局,flux来管理数据流动
初级阶段
- es6语法
- promis
- async,waite
- lodash:是具有一致接口,模块化,高性能等特性的JavaScript工具库。
- npm安装,react-native安装,环境搭建
- 了解Props,State
- 学习样式jxs,flexbox
- 学习导航器
进阶阶段
- es6语法
- 三个点参数用法(rest参数,spread操作符)
- 异步函数(Promise,Async)
- array操作(join,conact,map…)
- babel(es6转译es5)
- Object.assign(obj,…):扩展操作
- 柯里化(curry)函数:参数逐渐求值的过程
- compose函数
学习redux,了解它与flux的区别,学会如何使用单项数据流的思想管理状态树。它的使用场景会更多。你也可以看做它是简化了流程的flux。
- action
- reducer
- store
- middleWare
- redux-thunk:比较流行的redux异步action中间件,统一了异步和同步action的调用方式,避免在component动刀子。
学习Reselect:构建粒度化的数据,Reselect 库可以创建可记忆的(Memoized)、可组合的 selector 函数。Reselect selectors 可以用来高效地计算 Redux store 里的衍生数据。
- 学习react-native-drawer:可用于Android ios的抽屉式控件。
学习react-native-model-picker:一个比较好用的model picker,兼容Android iOS
学习redux-watch:一个可以检测全局store数据变动的组件,常用于全局的状态变化,比如登录数据:当发现token不一致时,弹出登录界面。比如全局检测错误数据:根据错误id显示不同的提示。
- 文件系统
- react-native-fs:react-native调用本地 文件系统的库,兼容Android iOS
- react-native-file-transfer:ios专用的从图片库往服务器上传库
- react-native-fileupload:兼容iOS Android上传文件的库。支持 1 同时上传多个文件 2 支持file and fields
- 导航
- react-native-router-flux:可配合redux的路由导航库,目前最全面,功能最强大。常用于构建整个APP的路由规则。
- react-native-scrollable-tab-view:带scroll滑动切换的tab view
- react-native-tabs:简版的底部tabbar导航栏,常见于ios应用,兼容Android iOS
- react-native-router-flux:可配合redux的路由导航库,目前最全面,功能最强大。常用于构建整个APP的路由规则。
解坑阶段
坑1:ipad 模拟器 command+D 程序崩溃
0.3.6才有的问题,ipad丢失了actionsheet布局
修复:
在React/Modules/RctDevMenu.m第519行新增
1 | UIAlertControllerStyle style = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? UIAlertControllerStyleActionSheet : UIAlertControllerStyleAlert; |
然后把519行的
1 | _actionSheet = [UIAlertController alertControllerWithTitle:title |
替换为
1 | _actionSheet = [UIAlertController alertControllerWithTitle:title |
android学习路线
初级阶段
技术要求:
- 四大组件Activity,Service, BroadcastReceive,ContentProvider的使用.参考文章
- Fragment
- ui设计
- 各类layout
- 简单自定义view,各种用户界面
- 动画[包括valueAnimator,ObjectAnimator]
- Bitmap,Canvas
- 数据存储
- sharePerference
- SQLite3,GreenDao,Realm
书籍推荐:
- 《Thinking in java》 经典
网站推荐:
- google api guides官方api,不知道怎么用,就看官方的
- 极客学院Android wiki非常全面
- Stack Overflow android tag
中级阶段
技术要求
- aidl:熟悉aidl,理解其工作原理,懂transact和onTransact的区别
- Binder:从java层大概理解Binder的工作原理,懂Parcel对象的使用
- 多进程:多进程的运行机制,消息队列,Messenger,Socket
- 事件分发:弹性滑动 滑动冲突
- 玩转view: view的绘制原理,各种自定义view
- 动画系列:熟悉view动画和属性动画的不同点,懂ObjectAnimator的工作原理
- 懂性能优化,熟悉mat等工具
- 熟悉常见的设计模式,比如mvp,mvvm
- 熟悉rxjava响应式编程
学习方法
- 阅读源码
- view以及事件分发
- view的滑动原理
- 如何实现弹性滑动
- view的滑动冲突
- view的measure,layout,draw
- 自己实现几个经典的view
高级阶段
技术要求
- 了解SystemSever的启动过程
- 了解AndroidFramework层的内容
- 了解主线程的消息循环模型
- 了解ams和psm的工作原理
- 了解Windows
- Activity的启动模式以及异常情况下不同Activity的表现
- Service的onBind和onReBind的关联
- onServiceDisconnected(ComponentName className)和binderDied()的区别
- AsyncTask在不同版本上的表现细节
- 线程池的细节和参数配置
总结
- 系统核心机制
- 基础知识点的细节
- 设计模式和架构
- 了解这张图的底层细节
推荐书籍
- 《android内核剖析》
android基础:控件集锦
汇总常用的或者经常忘记的Android控件
DrawerLayout
弹出式抽屉视图
DrawerLayout 控件的子视图必须是2个,1个显示原视图,1个显示弹出的抽屉视图
1 | <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" |
硬按键控制音量
1 添加权限<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
2 新建控制音量类实例
1 | //音量控制,初始化定义 |
3 实例初始化,在onCreat()
中:
1 | mAudioManager = (AudioManager) |
4 具体调节音量
1 | @Override |
home按键切换后台
1借用surface改变:
切换后台触发:
1 | public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { |
回到前台触发:
1 | public void surfaceCreated(SurfaceHolder arg0) { //activity resume |
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aty_securityissue_creat);
actionBar= getActionBar();
actionBar.show();
}1
2
3
//创建菜单
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
super.onCreateOptionsMenu(menu);
//添加菜单项
MenuItem add=menu.add(0,0,0,”add”);
MenuItem del=menu.add(0,0,0,”del”);
MenuItem save=menu.add(0,0,0,”save”);
//绑定到ActionBar
add.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
del.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
save.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return true;
}
//选择菜单
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case android.R.id.home:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
```
FragmentTabHost
python学习笔记:6 tornado
tornad是Facebook开源的非阻塞式web框架,类似于nodejs,主要是为了解决frendfeed的实时更新。因此相应速度非常高。
安装
win10环境:1
pip install tornado
mongodb数据库:官网下载地址
数据库请求
Mysql
Tornado-MySQL
,是对PyMySQL的异步化的一个库,测试用例,文档,都比较齐全,目前在使用的版本。
异步web请求
使用异步装饰器,实现异步功能1
2
3
4
5
6
7
8
9
10
11class TestAsynchr2(tornado.web.RequestHandler):
@tornado.web.asynchronous
@tornado.gen.engine
def get(self, *args, **kwargs):
client = tornado.httpclient.AsyncHTTPClient();
response = yield tornado.gen.Task(client.fetch,test_url)
body = json.loads(response.body)
print '异步请求2 %s' % body
print body['errNum']
self.write('异步请求2 %s' % response.body)
self.finish()
重点是yield,以及self.finish()
使用asyncmongo
,来异步的调用mongoDB服务器。它是专门给Tornado开发者开发提供异步数据库访问的
使用tornado进行长轮询
传统的方案是浏览器js进行定时http轮训,但是对服务器压力太大了。
新的技术是让浏览器发起连接来模拟服务器推送更新。这种方式的HTTP连接被称为长轮询或Comet请求。意味着浏览器只需启动一个http请求,其连接的服务器会有意保持开启,浏览器只需要等待更新可用时服务器”推送”响应。当服务器发送响应并关闭连接后,(或者浏览器端客户请求超时),客户端只需打开一个新的连接并等待下一个更新。
好处:
- 减少web服务器负载
- 浏览器兼容性,只要支持ajax即可
- 比如状态更新,消息通知,聊天消息,Twitter显示通知,Facebook的聊天
- 跟websockets的实现方式不同
常见问题
修改mysql默认字符集
最简单的方法:修改mysql的my.ini
配置文件.1
2default-character-set = utf8
character_set_server = utf8
python2.7查询mysql的中文乱码
解决方法:1
2
3
4
5
6
7
8
9
10reload(sys)
sys.setdefaultencoding('utf-8')
conn = yield tornado_mysql
.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='test',charset='utf8')
然后
print value.decode('utf-8')
如果是插入
则是value = unicode('你好',’utf-8')