有的同学在使用 git 时会不小心本地分支merge了远端的公共分支(通过 git pull ),我找了篇文章帮助大家学会 pull 的时候直接 rebase

[http://gitready.com/advanced/2009/02/11/pull-with-rebase.html](http://gitready.com/advanced/2009/02/11/pull-with-rebase.html)

其实很简单,对应的命令行是:

```bash
git pull --rebase  
```

由于 merge 提交会湮灭掉一些原始 commit 导致 rebase 时带来混乱,同时 merge 提交的 commit message 本身没有什么额外有价值的信息,我个人关于 merge 提交的经验是:

>如果你的角色是scm,代码集成者,多个分支隔离开发很长时间之后的合并建议使用merge;每天持续开发中的数量不多的提交都最好使用rebase,这样可以让提交记录尽量保持线性和整洁,进而方便代码的集成和追踪。

![](/uploads/2016_01_21_01.png)

尽管现在诞生的高级语言里边有了什么STM,协程,绿程的概念,但写代码总会遇到现实(商业级平台都不会用很新的东西)的多线程的问题。

比如有时候你需要同步的获取在另一个线程执行的代码的结果,在android里这种场景下ConditionVariable就非常好用了。

```java
if (Looper.myLooper() != Looper.getMainLooper()) {

final ConditionVariable completed = new ConditionVariable(); // 构造一个条件变量

view.runOnUiThread(new Runnable() {

@Override
public void run() {
try {
doSomeThingInUiThread(); // 将期望在另外线程做的事post出去
} finally { // finally很重要,防止运行时异常远跳转将ConditionVariable忘了open
completed.open(); // 事情办完了,notify到另外线程
}
}
});
completed.block(TIMEOUT_WAIT_UI); // 等着另外线程做的事完成,同时支持设置超时
} else {
doSomeThingInUiThread();
}
```

当然了以上是很简单的一个场景,使用ConditionVariable非常方便且够用。对于复杂的多线程之间的协同还是使用标准的条件变量结合lock + while 循环检查。

在一些新语言中有非常丰富的并发编程原语(future, delay, promise),特别是协程让我们用代码自主的确定代码流之间的协作关系而不是被动的作为OS调度器的奴隶,来支撑一些并行需求。

### [v8](https://developers.google.com/v8/)

支持jit,性能好,生态大,sdk 支持面向对象编程,上手容易,代码能够保持优雅;调试协议能被 chrome 支持;同时由于 [JIT](https://en.wikipedia.org/wiki/Just-in-time_compilation) 会在运行时生成额外的代码段,在iOS平台上发布时容易受限

### [Duktape](http://duktape.org/)

性能一般,但代码体积小,使用标准c开发,方便集成和嵌入其他项目;支持ES5.1的标准,文档和社区不错,开发起来经常需要掰着手指在那里计算堆栈入了多少次,出了多少次,刚开始会有点折磨;其作者对于开发和维护非常积极,基本上要求的特性只要社区呼声较高,他都会考虑添加进去,个人开发能力极强

Duktape 使用方面的其他文章请见标签 [Duktape](/tags/Duktape.html)

### [v7](https://github.com/cesanta/v7)

v7 性能是 non-JIT 引擎中较好的,但是对于ES规范的覆盖上不够,成熟度一般

### [Rhino](https://www.mozilla.org/rhino/)

rhino的爹是Mozilla,用java编写,可以在android上不用写JNI代码,容易集成,性能也不错,项目历史很悠久,成熟度很高(访问不了其官网的,请前往 [Github](https://github.com/mozilla/rhino)),但是存在很多不适合在线上环境中使用的特点:

* 在实际开发中,只要在java层bridge实现掉document、window之类对象后,这种对象的属性读写和方法调用都全部落到了java层,就在js域连document.xxx = yyy;这样的写法都不支持了,查完它的官方maillist都没办法实现。

* 在js侧用toString, print, JSON.stringify之类的方法容易将java层所有的方法和字段给反射出来,会有安全隐患

### 没事为什么要撸那么多js引擎

移动互联网年代客户端开发最痛苦的在于动态性,需求总有要变的时候,这时候一门灵活、能通过网络下载到客户端就地执行的语言就很重要了。而目前最合适的那门语言便是javascript。

由Mozilla开源的崩溃统计项目Socorro非常适合针对客户端的崩溃闪退、日志/堆栈上报,服务端进行采集、处理、分析、报告。

客户端的工作由类库[Breakpad](https://wiki.mozilla.org/Breakpad)完成。

服务端的工作由[Socorro](https://github.com/mozilla/socorro/)完成。

代码托管在[github](https://github.com/mozilla/socorro).

看这个提交和发布的数目,迭代程度还是挺深的。

这样针对移动开发,就不必重复造轮子了。

[Duktape](http://duktape.org/) 是一个体积小巧、可移植性高、适合嵌入到各种环境中的 JavaScript 引擎。

最近需要将 [protobuf.js](https://github.com/dcodeIO/protobuf.js) 移植到 Duktape 里边运行起来,所以需要解决 JavaScript 模块化加载问题,也就是要支持 require, module.exports 语法。我们通过 modSearch 函数来实现模块化加载:

#### 实现 modSearch 函数

[Implementing a native modSearch() function](http://wiki.duktape.org/HowtoModules.html)这篇 guide 里边有说通过在 native 实现 modSearch 函数就可以在 JavaScript 里通过require的时候加载到别的模块。

我在 c 层实现 modSearch 函数如下:

```c
//
// main.c
// duktape
//
// Created by faywong on 16/3/18.
// Copyright © 2016年 faywong. All rights reserved.
//

#include
#include "duktape.h"
#include "fileio.h"

duk_ret_t my_mod_search(duk_context *ctx) {
/*
* index 0: id (string)
* index 1: require (object)
* index 2: exports (object)
* index 3: module (object)
*/
printf("fun: %s in, id: %s\n", __FUNCTION__, duk_require_string(ctx, 0));

const char *id = duk_require_string(ctx, 0);
duk_pop_n(ctx, duk_get_top(ctx));

const int FILE_PATH_LEN = 1024;
char file[FILE_PATH_LEN];
memset(file, 0, FILE_PATH_LEN);
snprintf(file, FILE_PATH_LEN, "/Users/faywong/%s.js", id);

duk_push_string_file(ctx, file);
return 1;
}

/*
* Register Duktape.modSearch
*/
void register_mod_search(duk_context *ctx) {
duk_eval_string(ctx, "(function (fun) { Duktape.modSearch = fun; })");
duk_push_c_function(ctx, my_mod_search, 4 /*nargs*/);
duk_call(ctx, 1);
duk_pop(ctx);
}

int main(int argc, const char * argv[]) {

duk_context *ctx = duk_create_heap_default();

if (ctx) {

register_mod_search(ctx);

register_fileio(ctx);

duk_eval_file(ctx, "/Users/faywong/test.js");
printf("result is: %s\n", duk_safe_to_string(ctx, -1));
duk_pop(ctx);
}

return 0;
}
```

test.js 用以验证实现的模块化加载功能是否正常,内容如下:
```JavaScript
var ByteBuffer = require('bytebuffer');
var test = new ByteBuffer(10);
print('step 1, ByteBuffer ok: ' + test.toString());
var ProtoBuf = require('protobuf');
print('step 2, ProtoBuf ok: ' + (typeof ProtoBuf));
print('step 3, typeof ProtoBuf.loadProtoFile: ' + (typeof ProtoBuf.loadProtoFile));
var builder = ProtoBuf.loadProtoFile('/Users/faywong/complex.proto');
print('step 4, typeof builder: ' + (typeof builder));

Game = builder.build("Game"),
Car = Game.Cars.Car;

// OR: Construct with values from an object, implicit message creation (address) and enum values as strings:
var car = new Car({
"model": "Rustywq",
"vendor": {
"name": "Iron Inc.",
"address": {
"country": "US"
}
},
"speed": "SUPERFAST" // also equivalent to "speed": 2
});

// OR: It's also possible to mix all of this!

// Afterwards, just encode your message:
var buffer = car.encode();

print('step 5, typeof buffer: ' + (typeof buffer) + ' toString(): ' + buffer.toString());
```

其中:
* **register\_mod\_search** 函数用于向 Duktape 注册一个用于加载 JavaScript 模块的函数 **my\_mod\_search**,该函数有四个入参,分别为模块 id、发起 require 的模块、本模块的 exports 对象、本模块的 module 对象,该函数加载 /Users/faywong 目录下以 id 为主文件名(比如在 test.js 中 require 到的 bytebuffer, protobuf)的 JavaScript 文件并将文件内容返回给 Duktape

* 为了方便,test.js 中 require 的其他 JavaScript 模块被笔者放在了自己的家目录下:
```bash
/Users/faywong/bytebuffer.js
/Users/faywong/protobuf.js
/Users/faywong/test.js
```