lodash简介

发布在 node.js

image

简介

Lodash是一个著名的javascript原生库,不需要引入其他第三方依赖。是一个意在提高开发者效率,提高JS原生方法性能的JS库。

如何提高开发者效率了?

将许多代码简化为一个简单的方法名,只需要调用就行了。

下面是一个很简单的例子copy一个JS对象,避免指针问题

1
//copy一个JS对象

//原生方法
var a = {a:1,b:2,c:3};
var b = {};
for(var key in a) {
  b[key] = a[key];
}


//lodash方法
var b = _.clone(a);

如何提高JS原生方法性能?

使用惰性计算的方式

还是以事实说话

1
var array = [];
//生成一个100w 长度的数组,并赋值随机数
for(var i=0;i<1000000;i++) {
  array.push(Math.floor(Math.random()*10000))
}

//lodash forEach 遍历
console.time('lodash for Each');
_.forEach(array,function (key) {

});
console.timeEnd('lodash for Each');

//原生forEach 遍历
console.time('native for Each');
array.forEach(function (key) {

});
console.timeEnd('native for Each');

让我们来看一下上面运行的结果

1
lodash for Each: 4ms
native for Each: 98ms

差别还是很惊人的,速度相差了近25倍。

当然并不是所有方法都会比原生的快,就拿一开始copy对象的方法来说,我们依旧跑一下测试

1
var a = {};
for(var i=0;i<1000000;i++) {
  a[i.toString()] = Math.floor(Math.random()*100000);
}

var b = {};
console.time('native copy');
for(var key in a) {
  b[key] = a[key];
}
console.timeEnd('native copy');


var c = {};
console.time('lodash clone');
c = _.clone(a);
console.timeEnd('lodash clone');

结果

1
native copy: 669ms
lodash clone: 731ms

运行结果没有很明显的差别,但我们也只是为了证明我们上面的结论,并不是所有方法都比原生的快。

十分顺眼的”_”

Lodash使用了一个简单的 符号,就像Jquery的$一样,十分简洁,但是很显然 要看上去更爽的多~(个人观点),这也是我十分钟爱Lodash的主要原因之一。

常用的方法介绍

上面说了_十分简洁,同样的,在使用方法的时候也是十分简洁与方便的,下面列一下大家常用的方法。

  • _.forEach()
  • _.map()
  • _.isEmpty(value) //判断一个value 是否是empty(null,[],{}….)
  • _.find()
  • _.merge()
  • ….

Lodash我用Dash看的是有231个方法,各种你需要的原生方法基本都可以通过Lodash 直接或间接地完成,至于好不好用,也只有你用了才知道。

PS

lazy.js给出的性能对比图片

image

支持的浏览器以及Node各种版本

image

Lodash文档地址

注释和共享

Promise模式

发布在 node.js

Promise简介

我们都知道javascript最令人头痛的问题就是异步问题,所以理所当然的产生了许多解决异步问题的方案,例如在Node.js中(下文中介绍也是Node.js),async,es6 generator等都是很好的解决方案,而在这里我们介绍的是Promise模式。而我们做举例的插件是 bluebird

catch error

之所以接触promise也是因为try catch的问题,当时发现try catch竟然可以捕获 callback方法里面的error,当时感觉到很无语,之后被人推荐才接触了promise。
promise提供了捕获错误的机制,例如下面代码

1
new Promise(function (fulfilled, rejected){
  var name = yuansc.name;
}).catch(function (e) {
    console.log('error:',e);
  })

如下代码就可以直接捕获异常,而且免去了写try catch的麻烦,打印如下

1
error: [ReferenceError: yuansc is not defined]

callback方法的使用

很多时候我们需要用到callback的方法,那么promise怎么使用callback呢

1
function callbackTest(callback) {
  return  new Promise(function (fuifilled, rejected) {
    fs.readFile('./file1', function(err, result) {
      if(err) {
    	rejected(err);
      }
      fuifilled(result);
    })
  }).nodeify(callback);
}
callbackTest(function (err, result) {
  console.log(err, result.toString());
});

根据上面代码我们可以看到promise一开始接收两个参数 fulfilled,以及rejected,当你使用这两个方法的是时候 rejected代表着callback第一个选项,fulfilled则对应着第二个选项,如果对应err,result的话,那么rejected是err, fulfilled 对应着result.

return Promise

promise很大的特点是你使用的时候可以继续返回一个promise对象,可以继续沿用promise的属性

1
function returnPromise() {
  return  new Promise(function (fulfilled, rejected) {
    fs.readFile('./file1', function(err, result) {
      if(err) {
        rejected(err);
      }
      fulfilled(result);
    })
  })
}
returnPromise().then(function (result) {
  console.log("result", result.toString());
}).catch(function (e) {
  console.log("error", e);
});

这样就达到了promise沿用的效果

then的沿用

then是promise很著名的一个关键字,而then也确实十分好用

1
function dothen() {
  return new Promise(function (fulfilled, rejected) {
    fulfilled("hello");
  }).then(function (value) {
      return value +" world"
    }).then(function (value) {
      console.log(value);
    })
}

这句话打印之后会是

1
hello world

PS

介绍不是很全面,更多细节请点击下面API
源代码
API

注释和共享

我们在开发的过程中经常为遇到生成唯一标识符的情况,一个订单,一笔交易,等等。

以前

先上以前的代码:

1
var time=new Date().getTime();
  var randomNum=Math.floor(Math.random()*1000+1);
  return ''+time+randomNum;

很麻烦而且唯一性并不是很好。

node-uuid

在这里给大家介绍一种比较方便的生成方式:

浏览器

1
<script src="uuid.js"></script>

// Generate a v1 (time-based) id
uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'

// Generate a v4 (random) id
uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'

###node.js

1
npm install node-uuid
var uuid = require('node-uuid');

// Generate a v1 (time-based) id
uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'

// Generate a v4 (random) id
uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'

具体详情:点这

注释和共享

准备

  • 安装node.js开发环境(略过,不知道的请google);
  • 了解cheerio库,英文好的点这,英文没那么好的点这
  • 熟悉async(非必须),只是我比较喜欢用这个,之前写过一篇博客,大家可以看下
  • 了解node.js HTTP模块

查看页面结构

明确数据抓取页

这一步是为了分析你要抓数据的可行性,说白了就是看查看页面源代码分析其dom节点。在这里我们以58同城的租房栏最为目标数据抓取页。

分析dom节点

大家可以看源代码,我们要抓取的数据都是包含在一个一个table标签里面,table下面的每一个tr都是一条目标数据。

编码

这里先把代码放上–gist,以便大家可以对照看下面的讲解。
ok,下面进入最重要的一步,编码
我们使用的是node.js http get请求;

获取你要抓取的总页数

(你总不能抓一页就完事吧,要抓完)

1
function getPageNum(callback){
var options = {
host: host,
port: 80,
path: path,
headers: {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36'
}
};
var html = ""
http.get(options,function (res) {
res.on('data', function (data) {
html += data;
});
res.on('end', function () {
var $ = cheerio.load(html);
var pagenum=$('.pager').find('a').length;
var pager=$('.pager').find('a').eq(pagenum-2).text();
callback(undefined,pager);
});
}).on('error', function (e) {
callback(e);
})
}

上面我们定义了一个方法,发送http请求获取总的页数,
大部分都是http get请求的代码。核心代码:

1
var $ = cheerio.load(html);
var pagenum=$('.pager').find('a').length;
var pager=$('.pager').find('a').eq(pagenum-2).text();

在这一行里,大家可以查看页面源代码,发现其在 class:pager
的标签里包含着页数,而其中包含着好多a标签。而总页码数位于倒数第二个a标签中所以在上面我们可以获取总页数。

抓取数据

先上代码

1
function gettitle(path2,callback){
     var options = {
        host: host,
        port: 80,
        path: path+path2,
        headers: {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36'
        }
    };
    var html = ""
    http.get(options,function (res) {
        res.on('data', function (data) {
            html += data;
        });
        res.on('end', function () {
            var $ = cheerio.load(html);
             $('.main').find('table').find('tr').each(function(i,ele){
             	title.push($(this).find('h1').find('a').text().trim());
             });
             callback()
 
        });
    }).on('error', function (e) {
    	callback(e);
        })
}

从网页的源代码可以看出我们房屋信息的列表去全都包在一个个table的tr中,
所以我们首先找到其中的table,再选出其中的tr标签,然后对每个tr进行操作,摘出
其中的房屋题目。

PS:

由于这篇文章断断续续写的,所以到后期写的细节方面多有不足,
对应着我写的博客,和代码相对容易明白一点,但是首要因素是
明白async 和 http get请求。

注释和共享

写给使用node.js+mongodb的新人

准备工作

1
npm install mongodb

这是我们接下来要使用的一个第三方模块

组件下载

请点击:github

将此组件放到你项目目录下

1
config.js //数据库配置文件
DataProvider.js //普通文档数据操作方法文件
BinaryProvider.js //文件操作方法文件

使用方法

  • 配置config.js为你需要操作的数据库
  • 在/modules/dao文件夹下新建一个js文件,如UserProvider,其中this.collectionName为你选择的表名称
  • 新建一个userTest.js 引入组件

    1
    var UserProvider=require('./module/dao/UserProvider').UserProvider;
    var userProvder=new UserProvider();

文档数据操作

插入操作
1
function insert(){
    userProvder.insert({name:"yuansc"},{},function(err,result){
        console.log(err,result)
    })
}

这样你便完成插入一条名为{name:yuansc}的数据

查询操作
1
function find(){
    userProvder.find({name:'yuansc'},{},function(err,result){
        console.log(err,result)
    })
}

这样写便可以查询出你想要的数据,提示:你查询出来的result为数组

单条查询
1
function findOne(){
    userProvder.findOne({name:'yuansc'},{},function(err,result){
        console.log(err,result)
    })
}

这样可直接查找单条数据,result为json格式

其他

其他操作方式大家请看DataProvider.js有很多,,

文件操作

引入
1
var BinaryPrivider=require("../../module/BinaryProvider").BinaryProvider;
var binaryProvider=new BinaryPrivider();
存储图片
1
function save() {
    fs.readFile(path, function (err, data) {
        if (err) {
            console.log(err)
        } else {
            var imageID = new ObjectID();
            binaryProvider.write(data, fileType, filename, imageID, function (err, result) {
                if (err) {
                    console.log(err);
                } else {
                    console.log("success")
                }
            })
        }
    })
}

存取图片之前要先将图片转化为binary数据,然后通过write方法写入。fileType为文件类型,fileName为文件名称,imageID为生成的唯一标识

读取文件
1
function getPicture(){
    binaryProvider.read(new ObjectID(id),function(err,binaryData,fileType){
        if(err || result==null || result.length==0){
            console.log(err,result)
        }
        else
        {
           console.log("")
        }
    })
}

这是读取 id为数据库存储时的唯一标识
读取的数据位binary数据,你需要通过fs模块存储为文件,或者可直接将数据发送出去

注释和共享

async的使用

发布在 node.js

用过node.js 有时候一定会为js的异步问题感到头痛,
之前写过一篇博客是用递归解决异步问题的,node.js使用递归解决异步性问题
这次要给大家介绍的是 一个第三方库 async

安装

1
npm install async

引用

1
var async=require('async');

基本语法

解决多个无关函数的异步问题
1
async.series({
    1:function(done){
        console.log(1);
        done();
    },
    2:function(done){
        console.log(2);
        done();
    },
    3:function(done){
        console.log(3);
        done()
    }
},function(err){
    console.log(err);
})

如上3个方法会依次执行,需要注意

  1. 当每个方法执行完之后,必须通过调用回调来表示已执行完当前方法,才会继续执行;
  2. 最后的是用来捕获异常,出现异常不会继续向下执行;
大量相同数据的处理

这跟上面的我写的递归解决是同样的思想,只不过代码更为简洁明了

1
var array=[1,2,3,4,5]
var itreator=function(item,finish){
    console.log(item);
    finish();
}
async.eachSeries(array,itreator,function(err){
    console.log("all finish");
})

上面代码中当出现异常,和所有执行结束后到会执行最后的

1
console.log("all finish");

跟之前的相似,出现异常不会向下执行,同样的对于正常情况下,只有所有数据都处理完后才会输入“all finish”;

参考文献

同样还有很多处理方式异步同步交叉使用等等吧,
本人用的不是很多,
还有其他的很多方法,这是我比较常用的,其他方式的使用请见 :
官方github
更多Demo

注释和共享

  • 第 1 页 共 1 页

yuansc

生命不息,奋斗不止


改变世界