mongodb 的笔记

1. mongodb 的连接数问题

每次接受一个请求,打开数据库,然后将其关闭。像下面这样:

1
2
3
4
5
6
7
8
app.get('/detail/:id',function(req,res){
MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
db.findOne({_id:ObjectId(req.params.id)},function(err,result){
// do sth
db.close()
})
});
})

直觉有点浪费,每次 request 都重新建立 db connection,用完后又关掉,对于高并发的应用来说,尤其浪费。

所以,更好的方式是复用db connection,以下代码摘自 mongodb node native 官方例子:

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
var express = require('express');
var mongodb = require('mongodb');
var app = express();
var MongoClient = require('mongodb').MongoClient;
var db;
// Initialize connection once
MongoClient.connect("mongodb://localhost:27017/integration_test", function(err, database) {
if(err) throw err;
db = database;
// Start the application after the database connection is ready
app.listen(3000);
console.log("Listening on port 3000");
});
// Reuse database object in request handlers
app.get("/", function(req, res) {
db.collection("replicaset_mongo_client_collection").find({}, function(err, docs) {
docs.each(function(err, doc) {
if(doc) {
console.log(doc);
}else {
res.end();
}
});
});
});

应用初始化时,就建立一个 db 实例,以后所有的连接,都是使用这个 db connection。

并且,通过上面方式建立的 db connection 单独的连接,而是 connection pool,非常高效。


You open do MongoClient.connect once when your app boots up and reuse the db object. It’s not a singleton connection pool each .connect creates a new connection pool. [4]


更进一步,API 还提供了 maxPoolSize 选项,设置连接池的最大值,默认为 5 http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html

### 2. mongodb 连接失败导致 node crash

见 stackoverflow 上的问题 How to ensure Node.js keeps running after MonogBD connection drops? [1],如何让 Node.js 在数据库挂掉后继续跑? 目前没有特别好的解决方案。

首先描述下问题,创建一个 mongodb client:

1
2
3
MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
// do sth
});

当db连接断掉后(可以手动kill掉mongod进程来模拟复现当掉的情况),再访问 web 服务,就会出现下面类似的出错:

1
Error: failed to connect to [localhost:27017]

这时候web服务也宕掉了……

理想的情况是,希望出现一个 500 内部错误提示界面,或者提示在升级什么的,但是数据库连接断掉以后,(我猜测)是 throw 了一个 Error 出来,导致 Node 的主进程挂掉了

其中一个解决方案是,将数据库的连接操作放在 domain 中。

1
2
3
4
5
6
7
8
9
10
var d = require('domain').create();
d.on('error', function(er) {
console.log('Oh no, something wrong with DB');
});
d.run(function() {
// 这里使用的是 mongoose
mongoose.connect(config.db, options);
});

domain 的介绍见 文档 http://nodejs.org/api/domain.html, 不过,有点要注意就是 domain 还不够稳定 ,文档标注的是 unstable
不过,附录[1] 说已经用于生产环境中了,并且没有发现啥问题。

3. 总结:数据库连接可以复用;为保证数据库挂掉后,Node.js 主进程仍然继续跑,可以将数据可的连接操作放到 domain 模块中

4. 附录:mongolab 上的一篇博文 Deep Dive into Connection Pooling [3]

参考

[1] http://stackoverflow.com/questions/20689768/how-to-ensure-node-js-keeps-running-after-monogbd-connection-drops/20690008#20690008

[2] http://stackoverflow.com/questions/10656574/how-to-manage-mongodb-connections-in-a-nodejs-webapp

[3] http://blog.mongolab.com/2013/11/deep-dive-into-connection-pooling/ 介绍两种数据库连接方式,一种复用(好),一种不复用(坏)

[4] https://groups.google.com/forum/#!msg/node-mongodb-native/mSGnnuG8C1o/Hiaqvdu1bWoJ

两个hybrid手机开发UI框架

第一个版本:基于chocolatechip-ui

做了一个手机APP练手,一个月前上线了一个非常简单的版本。

v1_1

v1_2

v1_3

v1_4

v1_5

第二个版本:基于 ionic

ios_1

ios_3

使用下来的一些感受

  1. chocolatechip-ui 只是一个UI框架,UI的展示逻辑需要开发者自己处理,亮点在于在不同的平台下,自动匹配到相应的系统UI风格;
  2. http://ionicframework.com/ 只有一套UI风格,就是iOS 7扁平化的风格,ionic 与 AngularJs 进行了深度绑定,如果熟悉mvvm的开发风格的话,开发起来会非常快,不过曲线略微陡峭,不过 ionic 作为UI单独使用也是可以的
  3. 感觉 ionic 提供更为华丽的组件,而且官方的开发论坛也非常活跃,作为一名f2e,学下Angular自是不在话下,第二版的APP,加上学习Angular也就花了4天时间。

买了一口锅

做饭既是让人享受又十分浪费时间的事情,一天做两顿饭,饭后忍不住还看下电视,基本就
花费了5个小时左右,要是再起的晚,9、10点钟才起,白天真的就所剩不多了。在知乎上逛,
[1]发现一个特别适合一个人做饭的神器——塔吉锅。当时看到,没有立马下单,因为有人一起住,
大家轮流着做饭,倒还可以忍受,最近人少了,没人做饭了,于是准备入手一个。

tajiguo

探索下发现,这货的最大毛病就是粘锅!!!

zhanguo

于是,搜索搜索,发现了一口不锈钢不粘锅,已下单。等待尝试……

myguo

[1] http://www.zhihu.com/question/22515987

睡眠改善计划 (bbc纪录片:睡眠十律 )

我睡眠一直不太好,晚上睡不着,早上起不来,很累。看到 BBC 有个纪录片「睡眠十律」,于是记录下来,试着改善自己的睡眠

中文翻译为「睡眠十律」,但是其实说「律」有点太过了,纪录片中对这些促进睡眠的方式并没有下结论,保证有效,只是一个科学教的探索罢了。所以,真的不一定有效。并且,十个方法对于普通人不一定可行,我在观看时,顺便对这十个方法做了简单的记录:

  1. 睡前 1h 泡个热水澡(在浴缸里),体内温度升高,然后让身体(内部)逐渐冷却,纪录片中说,冷会让人产生睡意。
  2. 睡眠时间限制计划:为期4周时间,每次在卧室只能呆6h,2:00到8:00,到了时间必须起床;刚开始可能非常痛苦,一旦打破了你生物时钟,你就赢了。
  3. 打盹儿补充睡眠:下午2点到5点通常容易打盹,每次建议30min-60min。其它时间尽量控制。片中主要针对以为海上航行的运动员,睡眠不充足,通过打盹补充回来。
  4. 治疗齁声:睡眠后,呼吸道肌肉松弛下来,呼吸道变窄,呼吸时,口腔、鼻腔、软组织发生振动,产生齁声。两种方式,通过在嘴里含东西。没有说更多的东西。
  5. 酒精和咖啡对睡眠的影响:都是不好的。咖啡伤人难以入睡;酒精促进人入睡,但是睡眠的后半部分质量可能比较差。
  6. 利用「蓝光灯」来影响体内的激素水平,来提高起床后的精神状态:一种叫退黑色素的在夜间分泌,让人产生困意。如果利用光照,眼睛中一种特殊细胞受到刺激,会将信息传递给大脑,减退退黑色素的分泌,从而让人清醒——对于必须早起的人有效。片中以bbc的一个早间节目的主播为例。
  7. 食物影响睡眠:富含碳水化合物的食物让人更有睡意;蛋白质食物让人更加清醒。最好睡觉前4h小时进食。
  8. 食物钟控制睡眠——用来倒时差:16小时饥饿会激活食物钟(food clock)。所以,测试通过挨饿来同步食物钟,食物钟激活后(就是挨饿16h 后),会抑制睡眠,这个时候的第一顿按照当地时间的食物非常重要,这顿饭会将你的生物时钟调整为新时区的时间。所以「禁食旅行」吧。片中是以要全球参加比赛的运动员为例,帮助他们倒时差。
  9. 肌肉收紧放松练习:针对持续亢奋,精神状态太好以至于睡不着的人。睡前15min循环做全身肌肉收紧、放松,让自己放松下来。
  10. 自然疗法:薰衣草的味道让你放松;缬草也有类似功效。

纪录片中,这十个方法对于受测试的人都很有效,真是让人难以置信。

另外,知乎上也提到了一个方法:睡前看书,zhihu上说《高等数学》同济1版效果奇好

作为一般人,我觉得 1 、3 、9 倒是可以尝试下;女生也可以薰衣草的熏香。

我现在在尝试睡眠限制计划,有效果再补充!

使用google chrome抓取数据:抓取全国的高中

KEY WORDS : Chrome插件 数据抓取


1.数据源

正在做一个网站,需要全国的中学数据,中学数据比较全的应该是人人网了,简单搜索发现 http://xuexiao.eol.cn/ 也有比较全的数据,并且还有地址信息,所以决定不从人人网抓取了。

2.抓取数据的思路

作为一名「优秀」的前端工程师,当然使用 javascrpt 来抓取啦,浏览器提供了便捷的 API,处理 DOM 信息比写后端程序方便太多了。

查看「中国教育信息」黄页——黄页这种叫法好像是很多年前的事情了,可以看到三部分,挨个遍历下去,并处理分页抓取学校名称就可以了。

数据源

思路如下:

  1. 获取左边的省份列表
  2. 处理该省份的城市
  3. 然后挨个分页抓取就行了

3部分对应的主要代码如下(网站已经提供了 jQuery 了):

//1. function getAllProv(){
  return ["北京", "上海", "天津", "四川", "安徽", "江苏", "浙江", "辽宁", "山西", "福建", "广东", "广西", "海南", "河南", "湖南", "陕西", "湖北", "江西", "河北", "山东", "重庆", "青海", "吉林", "云南", "贵州", "甘肃", "宁夏", "新疆", "西藏", "内蒙古", "黑龙江"];
}
//2. function setCurrentCitiesOfProv(prov){
  return $.map($(".quyu_list a"),function(a){
                               var query = a.getAttribute('href');
                               var val = getQueryStringParameter(query,"local2");
                               return decodeURI(val.replace('_local2',''));
                             });
}
//3. function savePageData(){
  var prov = getCurrentProv();
  var city = getCurrentCityOfProv(prov);
  var schools = $('.right_box');
  var rows = [];
  $.map(schools,function(school){
    var name = $('h2',school).text().trim();
    var detail = $('h3',school).text().trim();
    var parts = detail.split(/\s+/);

    var row = {};
    row.name = name;
    // row.prov = decodeURI(prov);
    row.city = city;

    $.each(parts,function(i,item){
      var o = {
          "地址":"address",
          "邮编":"mailno",
          "电话":"phone"
      };
      var ab = item.split(':');
      var key = o[ab[0]];
      row[key] = ab[1];
    });
    rows.push(row);
  })
  saveStore(rows);// 存储本页的数据
}
注意,上面的脚本只表示了三个步骤,不能直接运行

3.将脚本封装为 Chrome 插件

单个页面的逻辑已经处理完毕了,怎么让浏览器自动抓取下去呢?答案很简单:将脚本变为 chrome 的一个插件,每次 http://xuexiao.eol.cn/ 这个站点的页面载入后,都执行上面写好的脚本就行了,每页的学校数据处理完毕后,脚本自动改变 url,刷新获取下页的数据。

实现一个 chrome 插件,使用 userscript 的方式是最简单的,安装好插件后,插件载入一个脚本,之行上面描述的三步逻辑,并且自动刷新到下面一页。这里比较关键的一个步骤是存储所有的省份、城市,并计算出下页的的 url 。具体请看后面附的完整代码。

那么具体怎么实现呢?

  1. 创建一个 manifest.json,这个是 chrome userscript 的声明文件
  2. 创建一个 contentscript.js (名字随意,但是在 manifest.json 中要对应),这个脚本的作用仅仅是一个脚本加载器,载入 script.js 执行页面数据抓取逻辑。为什么要这样做呢?因为contentscript.js的之行环境和真是页面的执行环境是隔离的,也就是说contentscript.js的一个变量和页面中的变量可以独立存在,它们属于两个世界,这样做的好处在于,比如你可以独立的运行不同版本的jQuery,而不冲突。 javascript 虽独立运行,但是 dom 接口却是共享的,比如 document.createElement(‘script’) 创建一个脚本并插入到 dom 中,可以实现网页面载入一个脚本的目的, 可以将插件中的 script.js 插入运行中的文档中,每次页面载入都会执行 script.js 。
  3. 创建一个 script.js (名字随意,但是在 manifest.json 中要对应),用于处理真正的数据抓取逻辑。script.js 会将得到的数据存入 localStorage 中,那么所有载入的页面就可以共享这个数据了。

由于写文章的时候,数据抓取工作还没有完成,就不附上抓取的数据了,页面每秒中才刷新一次,并且只有一个页面在跑,比较慢。要数据的请联系我。

4.插件代码

https://github.com/WeweTom/chrome-extension-data-picker

使用google 地图做路线规划

KEY WORDS : google 地图 , 路书 , 地图旅游路线攻略


google的地图服务非常强大,这次就用它来做旅游路线攻略
Google Maps Engine

通常我们使用的是google maps https://maps.google.com.hk/ 这个服务,但是其实google
还有另一个地图服务,用于满足自定义地图的需求,这个服务就是 Google Maps Engine 。

这个服务有两个版本,免费版本只能创建两个图层,更多介绍可看 [1]

这个服务应该是今年3月份左右才推出的 [2],谷歌此前曾推出一个类似的地图定制工具My Maps

制作你自己的地图

A. 进入google地图,https://maps.google.com.hk,点击"制作地图

map

B. 可以创建一个地图,或者选择之前已经建好的地图

map

C. 点击地图标题,给你的地图命名

map

D. 点击”添加图层“
Google Maps Engine免费版本只提供两个图层,外加一个搜索结果层。
地图上可以放置有点和路线,点就是想去的地方,比如说西湖十景,就是十个点,十个标注。

这样创建两个图层,像下面这样,两个图层可以取个名字

map

map

E. 添加你你的兴趣点,比如景点、吃饭的地儿

a. 这些点可以是地图上默认就识别的,通过搜索框就可以搜索出来,搜索出来的点可以添加到地图

map

map

map

b. 或者你自己标注的点,方法是点上左上那个标注,然后在地图上点击

map

这样,标注好所有你想去的点了,每个点可以设置不同的颜色 , 黄色的是起点表示杭州火车东站,像下面这样:

map

F. 将点连接起来——路线规划

如何高效的将所有的点都去一遍呢,这个时候你需要规划路线

a. 点击路线图标

map

b. 添加起点(注意可以从你之前添加的点中选取地点)

map

map

c. 添加目的地(我发现了,mapengine 现在中文支持还不够好,需要给你的地点加个英文前缀,当是标号吧)

map

d. 添加多个目的地 (这里有限制,加上起点总共不能超过10个点,所以要节约着用,应该选取几个关键的连接点)

map

e. 把所有的地点都连上

map

G. 在手机上安装google map engine,打开”我的地图“,就可以看到自己规划好的路线了

外出手机在手,心中有路,从此不再迷惘

[完]

[1] http://www.williamlong.info/archives/3643.html

[2] http://www.williamlong.info/archives/3420.html

nodejs 中调用java

java由于其历史悠久,有很多有用的jar包,nodejs作为比较新的平台,相比之下还是有所欠
缺的。本篇文章介绍如何在nodejs中调用java程序,这样既能用你熟悉的js语言,又能享用
java的成熟工具。

下面以nodejs中调用 yuicompressor.jar 这个jar包进行压缩的示例来说明node调用java的
完整过程——尽管yuicompressor.jar已经很大程度上被uglifyjs代替了。

类似的,这个例子也可以调用 google 的压缩工具 compiler.jar

windows 环境中 nodejs 调用 java

  1. 确保你已经正确的安装了java,你可以通过下面的代码来检查是否安装成功
java -version

若看到类似下面的截图,表示安装成功了
Alt Text

  1. 用nodejs封装cmdline下的命令

下载yuicompressor.jar ,建立一个测试文件test.js,内容随便写点什么

在windows命令行中,压缩这个js的命令是:

java -jar yuicompressor.jar test.js

上面的命令实际上完整的是(windows有个cmd.exe来完成实际的工作)

cmd /c java -jar yuicompressor.jar test.js

nodejs提供了spawn工具来执行外部程序命令,详见 nodejs文档

完整的代码如下

var spawn = require('child_process').spawn;


exe(["/c","java","-jar","yuicompressor.jar","test.js"]);
// 相当于在命令行下执行 cmd /c java -jar yuicompressor.jar test.js
// 也可以加入更多的参数

function exe(command){
    // windows下 
    var cmd = spawn("cmd",command);

    cmd.stdout.setEncoding("ASCII");
    cmd.stdout.on("data",function(data){
    console.log("------------------------------");
    console.log("exec",command);
    console.log("stdout:"+data);
    });

    cmd.stderr.on("data",function(data){
    console.log("------------------------------");
    console.log("stderr:"+data);
    console.log("------------------------------");
    });

    cmd.on("exit",function(code){
    console.log("exited with code:"+code);
    console.log("------------------------------");
    });
};

将上面的代码保存为 node-compress.js,执行即可

node node-compress.js

linux 版本

linux 调用java不用像windows 那样:

cmd /c java -jar yuicompressor.jar test.js

而是直接调用

java -jar yuicompressor.jar test.js

即可

所以完整的代码是:

var spawn = require('child_process').spawn;

exe(["-jar","yuicompressor.jar","test.js"]);
// 相当于在命令行下执行 java -jar yuicompressor.jar test.js

function exe(command){

    // linux下,不用 cmd /c java -jar yuicompressor.jar test.js,这种形式,直接
    // java -jar yuicompressor.jar test.js 即可
    var cmd = spawn("java",command);

    cmd.stdout.setEncoding("ASCII");
    cmd.stdout.on("data",function(data){
    console.log("------------------------------");
    console.log("exec",command);
    console.log("stdout:"+data);
    });

    cmd.stderr.on("data",function(data){
    console.log("------------------------------");
    console.log("stderr:"+data);
    console.log("------------------------------");
    });

    cmd.on("exit",function(code){
    console.log("exited with code:"+code);
    console.log("------------------------------");
    });
};

raphaeljs 在 IE8 下性能差的问题及解决方案

Raphaël 具有良好的兼容——IE能兼容到ie6,非常适合国情,但是情况正在发生变化,尤其是
在国外,考虑到IE9以及其他浏览器的份额,Raphaël 的作者推出了一个叫 Snap.svg
图形库,跟Raphaël 不同,Snap.svg完全是基于svg的图行库,少了些束手束脚。

不过在国内,ie6/7/8/仍然不可忽视,因此Raphaël 仍然是比较好的选择。

微软从IE9开始支持svg矢量图形技术,Raphaël 在 ie6/7/8 上使用的是专有的vml技术来模
拟svg的特性。

vml在IE8浏览器下性能非常之差

我们知道,直到IE9才支持svg,微软必须跟上开放标准的潮流,vml的没落就像很多IE其它专
有特性一样,渐渐被抛弃,到IE8最终发布的时候,对vml的支持已经非常不好了 [1]


“vml\:*”这个选择器被IE8认为不合法

并且,相比IE6/7,IE8下vml性能问题差了很多,可以看 stackoverflow上的一个用户测试

测试代码如下:

<script src="http://fiddle.jshell.net/js/lib/raphael-1.5.2-min.js"></script>
<div id="time-result"></div>
<div id="canvas"></div>
<script>
window.onload = function() {
    var timer = new Date();
    var paper = Raphael('canvas', 400, 400);
    var length = 25;
    for (var i = 0; i < 10; i++) {
        for (var j = 0; j < 10; j++) {
        paper.rect(length * i, length * j, length, length);
        }
    }
    $('#time-result').text('Rendered in ' + (new Date() - timer) + ' milliseconds.');
};
</script>

Raphael IE8 性能差的应对方案

通过修改meta标签,让IE8运行在IE7模式下,于是有了

改进1

<meta http-equiv="X-UA-Compatible" content="IE=7" >

但是,如果仅仅是这样的化会误伤IE9 —— IE9 已经支持svg了,如果页面上还有这个声明的
化,那么IE9也会以IE7模式来渲染页面。抛弃svg而使用vml,这样显然是很不合理的。

我困惑了很久,想尝试使用IE的另一个奇葩特性——条件注释来避免这个问题:

改进2 ——失败的尝试

将meta标签放在条件注释中,像这样

<!doctype html>
<html>
  <head>
    <!--[if lt IE 9]>
    <meta http-equiv="X-UA-Compatible" content="IE=7">
    <![endif]-->
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>

  </body>
</html>

但是遗憾的是,浏览器根本就不识别这样注释后的meta标签,所以这种方案以失败告终

改进3 —— 通过在服务器返回的header中设置,这个方案我没亲自尝试过

但是,PHP使用者,可以尝试下面的方案 [2]

header("X-UA-Compatible: IE=7,IE=9");

改进4 —— 最终方案

因为,我找到了更好的方案了,其实很简单,只要在 方案1 的基础上,做一点改变

<meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" >

IE确实支持这样的写法,不过还是有坑的,在iframe下有问题,详细参看stackoverflow上的
讨论 [3]

[1] http://www.cnblogs.com/rubylouvre/archive/2009/10/12/1581891.html

[2] http://stackoverflow.com/questions/6156639/x-ua-compatible-is-set-to-ie-edge-but-it-still-doesnt-stop-compatibility-mode

[3] http://stackoverflow.com/questions/3413629/emulate-ie7-for-ie8-but-not-for-ie9-using-x-ua-compatible

ubuntu 13.10 通过chrome vnc viewer 插件连接 windows7

chrome 安装 vnc viewer 插件就不说了,具体看这里

关键在于,windows7 安装了vnc server 后,通过ubuntu上的vnc viewer 连接 不上的问题

原因在与,win7 默认开启了防火墙设置。具体解决步骤如下:

点击windows徽标,搜索防火墙,打开“高级安全 Windows防火墙”

step1

step2

step3

接下来下一步,到结束,起个名字再用vnc viewer 连接就能成功了

ubuntu 13.10 下面安装 grunt 报错

$ npm install grunt #产生报错
npm ERR! Error: No compatible version found: underscore.string@'~2.2.0rc'
npm ERR! Valid install targets:

原因是ubuntu13.10中的npm版本过低

$ npm -v
1.2.18

解决办法 ,用npm重新安装npm

$ sudo npm install npm -g