##mvc简介
mvc是一种常用的项目开发的结构,其中j2ee,thinkphp,以及express都是用这个架构

  • m:model,表示数据库或者数据结构,包括其增删改查等操作
  • v:view,展示视图,html
  • c:control,表示控制器,用来连接model和view,从model中取出数据,给view

##微信公众平台的mvc
微信公众平台本身是单入口的程序,由于并不需要具体的view进行展示,所以利用框架开发并不合适,在这个项目中,我们自己搭建一个类似mvc的框架进行开发

  • model:各种工具类util,主要包括userUtil,logUtil,msgUtil等等
  • control:msgHandler,由于微信公众平台主要是消息的传递转发,所以我们主要就是利用一个control进行消息操作
  • view:由于展示的东西不多,所以view模块不需要

##开发中的问题
1.model的封装性,由于模型是对数据库进行操作,我们自己写的model难免会需要其他model的数据,一开始开发的时候,我直接在model中新建需要引用的model的实例,然后进行操作,这样的方式虽然方便,却破坏了模块封装的特性,出现重复操作的问题,在开发中,出现过一次问题

Connection reset by peer

问题就是对象循环引用

##z-index 简介

  • 你定义的CSS中有position属性值为absolute、relative或fixed,用z-index此取值方可生效。
  • 此属性参数值越大,则被层叠在最上面。

button下面的名字

此处用来隐藏button,实际上并没有使button消失,而是利用z-index将其遮蔽

.bestbuy .bname{
    position: relative;
    background: #ffffff;    //很重要,保证button不会显示出来
    z-index: 10;
}

.bbtn{
    position:absolute;   //很重要,要操作动态效果必须是absolute
    z-index:4;
}

$(function(){

        $(".bbig li").each(function(){
            $(this).sfHover({
                hoverEvent: function(){
                    if ($(this).find(".gWindow").length > 0){
                        $(this).find(".yoke_hot_bbtn").hide();
                    }else{
                        $(this).find(".yoke_hot_bbtn").show();
                        $(this).find(".yoke_hot_bbtn").animate({top:"136px"},300);
                    }
                },
                outEvent: function(){
                    $(this).find(".yoke_hot_bbtn").animate({top:"161px"},300);
                }
            });
        });
    })

##背景
最近因为要帮别人做一个线上商城,找到了ecshop,学习了两天,做一下笔记

##模板修改

  • ecshop中library为主文件中引用的文件,将大的index分成一块一块的
  • ecshop中themes/moban/index.dwt为主页的文件

index.dwt中page_header.lbi : 主要包括收藏、登陆、注册,以及搜索、购物车、logo、主导航(menu)
category_tree_index.lbi : 是指 所有商品分类 以及子目录, class=’Areal’
index_ad.lbi : 表示轮播的五张图片
recommend_new.lbi : 新品
recommend_hot.lbi : 热卖商品
recommend_promotion.lbi : 特价商品(未显示)
recommend_best.lbi : 精品推荐
cat_articles.lbi : 公告区域
help.lbi
page_footer

##后台修改
后台利用php开发,通过smarty来传递参数到模板

$smarty->assign('zhan',    get_cat_articles('-1', 1, 20 ,''));

同时,不需要require对应模块,因为在init.php已经引入了文件

require(dirname(__FILE__) . '/includes/init.php');

##includes文件夹
主要是各种工具类文件,来获取各种数据

##AngularJS: API: ngResource/service/$resource
在使用之前首先要引入ng-resource相关文件
下面列举官方的Api
链接地址如下

##举例
‘use strict’;

/* Services */
var phonecatServices = angular.module('phonecatServices',['ngResource']);

phonecatServices.factory('Phone123', ['$resource', 
    function($resource){
        return $resource('phones/:phoneId.json',{}
            ,{query: {method:'GET',params:{phoneId:'phones'},isArray:true}
        });
    }
]);

$resource(url, [paramDefaults], [actions], options);

  • 第一个参数是访问资源的url
  • 第二个参数 Given a template /path/:verb and parameter {verb:’greet’, salutation:’Hello’} results in URL /path/greet?salutation=Hello,如果有@作为前缀,则有特殊处理(暂时没弄清楚)
  • 第三个参数在上例中表示phoneId用phones替代
  • 最后一个参数表示是数组

##生成talks模块
在应用程序的根目录,输入

yo meanjs:crud-module talks

响应提示:

  • 选择所有四个补充文件夹(css、img、directives 和 filters)。
  • 回答 Yes,将 CRUD 模块链接添加到菜单。
  • 当生成器询问要使用哪个菜单时,接受默认设置(topbar)。

如下所示

$ yo meanjs:crud-module talks
[?] Which supplemental folders would you like to include in your angular module? 
css, img, directives, filters
[?] Would you like to add the CRUD module links to a menu? Yes
[?] What is your menu identifier? topbar
   create app/controllers/talks.server.controller.js
   create app/models/talk.server.model.js
   create app/routes/talks.server.routes.js
   create app/tests/talk.server.model.test.js
   create public/modules/talks/config/talks.client.routes.js
   create public/modules/talks/controllers/talks.client.controller.js
   create public/modules/talks/services/talks.client.service.js
   create public/modules/talks/tests/talks.client.controller.test.js
   create public/modules/talks/config/talks.client.config.js
   create public/modules/talks/views/create-talk.client.view.html
   create public/modules/talks/views/edit-talk.client.view.html
   create public/modules/talks/views/list-talks.client.view.html
   create public/modules/talks/views/view-talk.client.view.html
   create public/modules/talks/talks.client.module.js

请注意,生成器创建了服务器端基础架构(保存在app目录中):路由、一个控制器、一个模型和一个单元测试。它还在 public/modules/talks 目录下构建了所有客户端工件。
稍后将向Talk对象添加一些自定义字段。在此之前,在浏览器中访问网站,查看默认情况下会得到哪些内容。
单击右上角的Signin链接,输入本系列早些时候创建的用户名和密码,或者单击Signup并创建一组新的凭证。
完成登录后,可以在左上角看到一个 Talks 菜单。从菜单中选择 New Talk 打开一个 HTML 表单,其中提供了一个独立的 Name 字段,

##添加字段
要向 Talk 添加新字段,必须编辑 6 个文件 — 四个用于显示,两个用于持久性:

app/models/talk.server.model.js
public/modules/controllers/talks.client.controller.js
public/modules/talks/views/create-talk.client.view.html
public/modules/talks/views/edit-talk.client.view.html
public/modules/talks/views/view-talk.client.view.html
public/modules/talks/views/list-talks.client.view.html

详细的大家可以自己去实现,实现方法也不难

##常用的Yeoman命令

###生成一个meanjs工程
yo meanjs

###生成一个CRUD模块

yo meanjs:crud-module <module-name>

###创建一个angularJS的模块
yo meanjs:angular-module

###创建一个angular-route
yo meanjs:angular-route

###同理有如下命令
yo meanjs:angular-controller
yo meanjs:angular-view
yo meanjs:angular-service
yo meanjs:angular-directive
yo meanjs:angular-filter
yo meanjs:angular-config
yo meanjs:angular-test
yo meanjs:express-model

##创建express相关命令
yo meanjs:express-controller
yo meanjs:express-route
yo meanjs:express-test

改教程主要是用时空隧道进行翻墙,每天免费使用2小时,亲测可用

##下载插件,并导入到chrome浏览器中
不会导入请自行百度,下载地址如下

链接: http://pan.baidu.com/s/1mgIeC3m 
密码: 89z4

##注册并填写邀请码

时空隧道邀请码 UvRxzd

完成上述步骤即可翻墙

本节主要介绍ui.router的使用

##代码
app.js

var bookApp = angular.module('bookApp',['ui.router']);

bookApp.config(function($stateProvider, $urlRouterProvider){
    $urlRouterProvider.otherwise('/index');
    $stateProvider
        .state('index',{
            url: '/index',
            views: {
                '': {
                    templateUrl: 'tpls/home.html'
                },
                'main@index': {
                    templateUrl: 'tpls/loginForm.html'
                }
            }
        })
});

上述实现了对index路径的差分,当访问 http://localhost:8080/app/#/index 时,
实际访问的是home.html,并且在home.html中存在“


将其中的main块填充为loginForm.html页面
具体代码见 https://github.com/zhanfang/angular_ui_router ,可能会随时更新

http://blog.fens.me/nodejs-karma-jasmine/

##前言

Nodejs领域: Jasmine做单元测试,Karma自动化完成单元测试,Grunt启动Karma统一项目管理,Yeoman最后封装成一个项目原型模板,npm做nodejs的包依赖管理,bower做javascript的包依赖管理。Java领域:JUnit做单元测试, Maven自动化单元测试,统一项目管理,构建项目原型模板,包依赖管理。

本文介绍Jasmine+Karma自动化单元测试。

##Karma的介绍

Karma是Testacular的新名字,在2012年google开源了Testacular,2013年Testacular改名为Karma。Karma是一个让人感到非常神秘的名字,表示佛教中的缘分,因果报应,比Cassandra这种名字更让人猜不透!

Karma是一个基于Node.js的JavaScript测试执行过程管理工具(Test Runner)。该工具可用于测试所有主流Web浏览器,也可集成到CI(Continuous integration)工具,也可和其他代码编辑器一起使用。这个测试工具的一个强大特性就是,它可以监控(Watch)文件的变化,然后自行执行,通过console.log显示测试结果。

Jasmine是单元测试框架,本单将介绍用Karma让Jasmine测试自动化完成。Jasmine的介绍,请参考文章:jasmine行为驱动,测试先行

istanbul是一个单元测试代码覆盖率检查工具,可以很直观地告诉我们,单元测试对代码的控制程度。

##Karma的安装

npm install karma --save-dev

# Install plugins that your project needs:
$ npm install karma-jasmine karma-chrome-launcher --save-dev

注意:该语句表示安装到当前目录下面

当你为你的模块安装一个依赖模块时,正常情况下你得先安装他们(在模块根目录下npm install module-name),然后连同版本号手动将他们添加到模块配置文件package.json中的依赖里(dependencies)。

-save和save-dev可以省掉你手动修改package.json文件的步骤。
npm install module-name -save 自动把模块和版本号添加到dependencies部分
npm install module-name -save-dve 自动把模块和版本号添加到devdependencies部分

启动karma,测试是否安装成功

./node_modules/karma/bin/karma start

除此之外我们还需要全局的karma-cli

安装方法

sudo npm install -g karma-cli

##Karma + Jasmine配置

初始化karma配置文件

karma init my.conf.js

Which testing framework do you want to use ?
Press tab to list possible options. Enter to move to the next question.
> jasmine

Do you want to use Require.js ?
This will add Require.js plugin.
Press tab to list possible options. Enter to move to the next question.
> no

Do you want to capture a browser automatically ?
Press tab to list possible options. Enter empty string to move to the next question.
> Chrome
> Firefox
>

What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.
> *.js
> test/**/*.js
>

Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.
>

Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.
> yes

##启动 Karma

karma start my.conf.js

##自动化单元测试

3步准备工作:

  1. 创建源文件:用于实现某种业务逻辑的文件,就是我们平时写的js脚本
  2. 创建测试文件:符合jasmineAPI的测试js脚本
  3. 修改karma.conf.js配置文件

###创建源文件:用于实现某种业务逻辑的文件,就是我们平时写的js脚本
有一个需求,要实现单词倒写的功能。如:”ABCD” ==> “DCBA”

~ vi src.js

function reverse(name){
    return name.split("").reverse().join("");
}

###创建测试文件:符合jasmineAPI的测试js脚本

describe("A suite of basic functions", function() {
    it("reverse word",function(){
        expect("DCBA").toEqual(reverse("ABCD"));
    });
});

###修改karma.conf.js配置文件
我们这里需要修改:files和exclude变量

module.exports = function (config) {
    config.set({
        basePath: '',
        frameworks: ['jasmine'],
        files: ['*.js'],
        exclude: ['karma.conf.js'],
        reporters: ['progress'],
        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: true,
        browsers: ['Chrome'],
        singleRun: false
    });
};

启动karma

单元测试全自动执行

$ karma start my.conf.js

INFO [karma]: Karma v0.12.31 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome 42.0.2311 (Mac OS X 10.10.2)]: Connected on socket HqiWljeM3m-UjEpQuk37 with id 17873649
Chrome 42.0.2311 (Mac OS X 10.10.2): Executed 1 of 1 SUCCESS (0 secs / 0.003 secChrome 42.0.2311 (Mac OS X 10.10.2): Executed 1 of 1 SUCCESS (0.015 secs / 0.003 secs)

浏览器会自动打开

我们修改test.js

~ vi test.js

describe("A suite of basic functions", function() {
    it("reverse word",function(){
        expect("DCBA").toEqual(reverse("ABCD"));
        expect("Conan").toEqual(reverse("nano"));
    });
});

由于karma.conf.js配置文件中autoWatch: true, 所以test.js文件保存后,会自动执行单元测试。

执行日志如下:提示我们单元测试出错了。

INFO [watcher]: Changed file "D:/workspace/javascript/karma/test.js".
Chrome 28.0.1500 (Windows 7) A suite of basic functions reverse word FAILED
        Expected 'Conan' to equal 'onan'.
        Error: Expected 'Conan' to equal 'onan'.
            at null. (D:/workspace/javascript/karma/test.js:4:25)
Chrome 28.0.1500 (Windows 7): Executed 1 of 1 (1 FAILED) ERROR (0.3 secs / 0.006 secs)

##Karma和istanbul代码覆盖率

增加代码覆盖率检查和报告,增加istanbul依赖

$ npm install karma-coverage --save-dev

修改karma.conf.js配置文件

$ vi karma.conf.js

reporters: ['progress','coverage'],
preprocessors : {'src.js': 'coverage'},
}

启动karma start,在工程目录下面找到index.html文件,coverage/chrome/index.html

打开后,我们看到代码测试覆盖绿报告

覆盖率是100%,说明我们完整了测试了src.js的功能。

接下来,我们修改src.js,增加一个if分支

function reverse(name){
    if(name=='AAA') return "BBB";
    return name.split("").reverse().join("");
}

再看覆盖率报告,

Statements:75%覆盖,Branches:50%覆盖。

为了产品的质量我们要尽量达到更多的覆盖率,一般对于JAVA项目来说,能达到80%就是相当高的标准了。对于Javascript的代码测试及覆盖率研究,我还要做更多的验证。

还有不明白的可以去我的github,下载完整版参考
https://github.com/zhanfang/karma_test

详情请参考 https://karma-runner.github.io/0.12/

基于nodejs的http接口

可以将机器上的任意一个目录变成可以通过浏览器访问的目录

模拟数据测试

主要用来向前端发送测试用的json数据

##安装方法

npm install http-server -g

##使用 :

在站点目录下开启命令行输入

node http-server

  

##使用于package.json

“scripts”: {
“start”: “http-server -a 0.0.0.0 -p 8000”,
}

##参数 :

-p 端口号 (默认 8080)

-a IP 地址 (默认 0.0.0.0)

-d 显示目录列表 (默认 'True')

-i 显示 autoIndex (默认 'True')

-e or --ext 如果没有提供默认的文件扩展名(默认 'html')

-s or --silent 禁止日志信息输出

--cors 启用 CORS via the Access-Control-Allow-Origin header

-o 在开始服务后打开浏览器

-h or --help 打印列表并退出

-c 为 cache-control max-age header 设置Cache time(秒) , e.g. -c10 for 10 seconds (defaults to '3600'). 禁用 caching, 则使用 -c-1.

##安装

###Yeoman方式

很多开发者都为MEAN开发了Yeo的生成器,使用yeoman的生成器就下面两步。先安装生成器

在系统上安装 Yeoman:

npm install -g yo

全局安装 MEAN.JS 生成器

npm install -g generator-meanjs

然后生成项目

yo meanjs

注意:由于.npm的权限问题可能导致yo安装失败,解决方法

sudo chown -R `whoami` ~/.npm

##启动
grunt

#1: 在开发环境使用nodemon,在生产环境使用pm2

当你第一次开发Node.js应用的时候, 其中一件事情就是一次又一次的运行[file].js 就和揭伤疤一样。 当我第一次开发的node app时候,这个让我感到异常挫败和痛苦, 尤其是每当我修改很小东西的时候需要control+c
幸运的是我发现了一个非常棒的工具Nodemon。 你可以利用以下的命令来安装

npm install -g nodemon

Nodemon 是一个令人惊叹的工具, 当你全局安装它以后, 可以通过 nodemon [file].js 来启动你的node.js scripts,它会告诉nodemon来监视你的script和scripts的所有变化, 这样的Node.js开发方式非常震撼以及让大大提高开发速度。

那么,生产环境又如何, 除非你用了heroku,Nodejitsu或者其它一些好的 Node.js 平台(也许它们有类似的功能), 但是碰巧你用了EC2 或者一些其它的云平台来运行你的Node.js app, 你如何能然保证这是一个始终运行的Node.js app
答案就是PM2, PM2 是一个类似于Nodemon的工具,不同之处在于它用于生产环境, 和Nodemon相似的地方在于它会监控你的app的任何修改或者重新部署,但是有更好的一面, PM2 在遭遇到崩溃的时候,它会正确重启你的app。

PM2的优胜之处在于当你要将app需要多核处理的时候,PM2内部集成的负载均衡可以让你很容易的去指定运行多少个实例。

pm2 start app.js -i max

-i参数目的是指定运行多少个实例,在这个例子中 PM2 使用了一个常量max来扩展你的app运转到你最大的核数,不要忘记Node 平时只会运行在单核!

##2: 轻松调试 Node.js apps

如果你从一个IDE重度集成的语言比如java 或者C# 转来调试Node.js, 你一定会感到很困扰, 大部分新加入node的开发者采用了’flow’的调试模式,从这一刻开始你最好的朋友就是console.log

但是依然有更常见的调试方式来代替, Node.js 内置了一个调试器你可以称为 node debug, 不过我更喜欢的 node-inspector

它们的github说 “Node Inspector 是一个使用Blink Developer Tools (以前称为WebKit Web Inspector)node.js调试器的界面,”

简而言之,node-inspector 可以让你用任何你想用的编辑器和chrome web tools来调试你的应用,这是多么的性感。

Node-inspector 可以让你做一些非常酷的事情,比如实时修改,单步调试,注入以及一堆其它非常酷的东西。

让我们来根据指示一步一步安装

https://github.com/node-inspector/node-inspector

##3.Nodefly

一旦你有你的应用程序正常运行,你可能会问自己,你怎么可以监视它的性能和配置文件,以确保您的应用程序运行在最佳的速度。最简单的答案是一个卓越的服务,我称为Nodefly。

用简单的一行代码Nodefly开始监视你的应用程序内存泄漏,测量redis用了多久,mongo查询和一堆其它很酷的东西。

http://www.nodefly.com

##4.不要检查node_modules 文件夹

虽然我们的话题一直是modules和npm,但是并不是不是很多人都知道,你不应该提交node_modules文件夹。这背后最大的原因是,没有必要提交这个文件夹。只要有人下载你的代码,它们可通过运行NPM来安装和下载所有需要的模块。

您可能会说,它是不是一个大问题,如果检查node_modules,但是,如果下载代码的人使用了和你编译modules不一样的操作系统的来安装通过NPM?你的应用程序将会崩溃,下载代码的人将不知道为什么会如此!

举个例子bcrypt以及sentimental如果当在您安装在主机系统上编译它们,因为它们用了本地C语言组件来编译。

避免检查node_modules文件夹的方式是加入.gitignore

// .gitignore node_modules/*

##5. 别忘记返回

初学者经常犯一个很常识的错误,就是忘记callback后的返回值,虽然有些时候,这没有影响,有很多时候,你会遇到奇怪的问题,因为你的回调被调用两次。

让我们看一个简单的例子

function do(err,result, callback){
   if(err){
      callback(“error”);
  }
  callback(“good”);
}

乍一看,这个片段是有道理的。如果有错误,在回调中发送“错误。如果不发送return,调用callaback后这个函数不会停下来。它只是将移动到调用回callback(“good”)。

这样做在长期和复杂的代码行里面会节省几个小时的调试。

##前言
一个新的web项目开始,我们总是很自然地去下载需要用到的js类库文件,比如jQuery,去官网下载名为jquery-1.10.2.min.js文件,放到我们的项目里。当项目又需要bootstrap的时候,我们会重复刚才的工作,去bootstrap官网下载对应的类库。如果bootstrap所依赖的jQuery并不是1.10.2,而是2.0.3时,我们会再重新下载一个对应版本的jQuery替换原来的。

包管理是个复杂的问题,我们要知道谁依赖谁,还要明确哪个版本依赖哪个版本。这些对于开发人员来说,负担过重了。bower作为一个js依赖管理的工具,提供一种理想包管理方式,借助了npm的一些思想,为我们提供一个舒服的开发环境。

你要还不动起手来试试bower,那你一定不会知道,前端开发是件多么享受的事。

##1. bower介绍
Bower 是 twitter 推出的一款包管理工具,基于nodejs的模块化思想,把功能分散到各个模块中,让模块和模块之间存在联系,通过 Bower 来管理模块间的这种联系。

包管理工具一般有以下的功能:

注册机制:每个包需要确定一个唯一的 ID 使得搜索和下载的时候能够正确匹配,所以包管理工具需要维护注册信息,可以依赖其他平台。
文件存储:确定文件存放的位置,下载的时候可以找到,当然这个地址在网络上是可访问的。
上传下载:这是工具的主要功能,能提高包使用的便利性。比如想用 jquery 只需要 install 一下就可以了,不用到处找下载。上传并不是必备的,根据文件存储的位置而定,但需要有一定的机制保障。
依赖分析:这也是包管理工具主要解决的问题之一,既然包之间是有联系的,那么下载的时候就需要处理他们之间的依赖。下载一个包的时候也需要下载依赖的包。
功能介绍,摘自文章:http://chuo.me/2013/02/twitter-bower.html

##2. bower安装

bower插件是通过npm, Node.js包管理器安装和管理的.

我的系统环境

win7 64bit
Nodejs:v0.10.5
Npm:1.2.19
~ D:\workspace\javascript>node -v
v0.10.5

~ D:\workspace\javascript>npm -v
1.2.19

在系统中,我们已经安装好了Nodejs和npm。win7安装nodejs请参考文章:Nodejs开发框架Express3.0开发手记–从零开始

###安装bower
全局安装bower

~ D:\workspace\javascript>npm install bower -g
新建一个express3的项目nodejs-bower


~ D:\workspace\javascript>express -e nodejs-bower
~ D:\workspace\javascript>cd nodejs-bower && npm install

##3. bower命令

bower安装后,我们就可以用bower这个命令了。

~ D:\workspace\javascript\nodejs-bower>bower
Usage:
    bower  [] []
Commands:
    cache                   Manage bower cache
    help                    Display help information about Bower
    home                    Opens a package homepage into your favorite browser
    info                    Info of a particular package
    init                    Interactively create a bower.json file
    install                 Install a package locally
    link                    Symlink a package folder
    list                    List local packages
    lookup                  Look up a package URL by name
    prune                   Removes local extraneous packages
    register                Register a package
    search                  Search for a package by name
    update                  Update a local package
    uninstall               Remove a local package
Options:
    -f, --force             Makes various commands more forceful
    -j, --json              Output consumable JSON
    -l, --log-level         What level of logs to report
    -o, --offline           Do not hit the network
    -q, --quiet             Only output important information
    -s, --silent            Do not output anything, besides errors
    -V, --verbose           Makes output more verbose
    --allow-root            Allows running commands as root
See 'bower help ' for more information on a specific command.

Commands,列出了bower支持的各种命令。

cache:bower缓存管理
help:显示Bower命令的帮助信息
home:通过浏览器打开一个包的github发布页
info:查看包的信息
init:创建bower.json文件
install:安装包到项目
link:在本地bower库建立一个项目链接
list:列出项目已安装的包
lookup:根据包名查询包的URL
prune:删除项目无关的包
register:注册一个包
search:搜索包
update:更新项目的包
uninstall:删除项目的包

##4. bower使用

###1). 安装jQuery到项目nodejs-bower

~ D:\workspace\javascript\nodejs-bower>bower install jquery
bower jquery#*              not-cached git://github.com/components/jquery.git#*
bower jquery#*                 resolve git://github.com/components/jquery.git#*
bower jquery#*                download https://github.com/components/jquery/archive/2.0.3.tar.gz
bower jquery#*                 extract archive.tar.gz
bower jquery#*                resolved git://github.com/components/jquery.git#2.0.3
bower jquery#~2.0.3            install jquery#2.0.3

jquery#2.0.3 bower_components\jquery

通过执行命令,我们可以看到jQuery的最新版本被下载,并安装到项目的bower_components\jquery目录

查看bower_components/jquery目录,发现了3个文件。

~ D:\workspace\javascript\nodejs-bower>ls bower_components/jquery -a
.  ..  .bower.json  component.json  jquery.js

同样地,我们的项目还需要d3的类库

~ D:\workspace\javascript\nodejs-bower>bower install d3
bower d3#*                  not-cached git://github.com/mbostock/d3.git#*
bower d3#*                     resolve git://github.com/mbostock/d3.git#*
bower d3#*                    download https://github.com/mbostock/d3/archive/v3.2.8.tar.gz
bower d3#*                     extract archive.tar.gz
bower d3#*                    resolved git://github.com/mbostock/d3.git#3.2.8
bower d3#~3.2.8                install d3#3.2.8

d3#3.2.8 bower_components\d3

非常方便,下载并安装完成!

###2). 查看项目中已导入的类库

~ D:\workspace\javascript\nodejs-bower>bower list
bower check-new     Checking for new versions of the project dependencies..
nodejs-bower#0.0.0 D:\workspace\javascript\nodejs-bower
├── d3#3.2.8
└── jquery#2.0.3

###3). 安装bootstrap库,并查看依赖情况

~ D:\workspace\javascript\nodejs-bower>bower install bootstrap
bower bootstrap#*               cached git://github.com/twbs/bootstrap.git#3.0.0-rc1
bower bootstrap#*             validate 3.0.0-rc1 against git://github.com/twbs/bootstrap.git#*
bower jquery#>= 1.9.0           cached git://github.com/components/jquery.git#2.0.3
bower jquery#>= 1.9.0         validate 2.0.3 against git://github.com/components/jquery.git#>= 1.9.0
bower bootstrap#~3.0.0-rc1     install bootstrap#3.0.0-rc1

bootstrap#3.0.0-rc1 bower_components\bootstrap
└── jquery#2.0.3

~ D:\workspace\javascript\nodejs-bower>bower list
bower check-new     Checking for new versions of the project dependencies..
nodejs-bower#0.0.0 D:\workspace\javascript\nodejs-bower
├─┬ bootstrap#3.0.0-rc1 extraneous
│ └── jquery#2.0.3
├── d3#3.2.8
└── jquery#2.0.3

我们发现bootstrap,对jquery是有依赖的。

###4). 删除jQuery库,破坏依赖关系

~ D:\workspace\javascript\nodejs-bower>bower uninstall jquery
bower conflict      bootstrap depends on jquery
Continue anyway? (y/n) y
bower uninstall     jquery

~ D:\workspace\javascript\nodejs-bower>bower list
bower check-new     Checking for new versions of the project dependencies..
nodejs-bower#0.0.0 D:\workspace\javascript\nodejs-bower
├─┬ bootstrap#3.0.0-rc1 extraneous
│ └── jquery missing
├── d3#3.2.8
└── jquery missing

###5). 安装低版本的jQuery,制造不版本兼容

~ D:\workspace\javascript\nodejs-bower>bower install jquery#1.7.2
bower jquery#~2.0.3             cached git://github.com/components/jquery.git#2.0.3
bower jquery#~2.0.3           validate 2.0.3 against git://github.com/components/jquery.git#~2.0.3
bower jquery#>= 1.9.0           cached git://github.com/components/jquery.git#2.0.3
bower jquery#>= 1.9.0         validate 2.0.3 against git://github.com/components/jquery.git#>= 1.9.0
bower jquery#1.7.2              cached git://github.com/components/jquery.git#1.7.2
bower jquery#1.7.2            validate 1.7.2 against git://github.com/components/jquery.git#1.7.2

Unable to find a suitable version for jquery, please choose one:
    1) jquery#1.7.2 which resolved to 1.7.2
    2) jquery#~2.0.3 which resolved to 2.0.3 and has nodejs-bower as dependants
    3) jquery#>= 1.9.0 which resolved to 2.0.3 and has bootstrap#3.0.0-rc1 as dependants

Prefix the choice with ! to persist it to bower.json

Choice: 1
bower jquery#1.7.2             install jquery#1.7.2

jquery#1.7.2 bower_components\jquery

~ D:\workspace\javascript\nodejs-bower>bower list
bower check-new     Checking for new versions of the project dependencies..
nodejs-bower#0.0.0 D:\workspace\javascript\nodejs-bower
├─┬ bootstrap#3.0.0-rc1 extraneous
│ └── jquery#1.7.2 incompatible with >= 1.9.0 (2.0.3 available)
├── d3#3.2.8
└── jquery#1.7.2 incompatible with ~2.0.3 (2.0.3 available)

我们可以清楚的看到bower,很明确的告诉了我们,jquery和bootstrap是不兼容的,强大之处大家应该有所体会。

###6).升级jQuery,让版本兼容

~ D:\workspace\javascript\nodejs-bower>bower update jquery
bower jquery#~2.0.3             cached git://github.com/components/jquery.git#2.0.3
bower jquery#~2.0.3           validate 2.0.3 against git://github.com/components/jquery.git#~2.0.3
bower jquery#>= 1.9.0           cached git://github.com/components/jquery.git#2.0.3
bower jquery#>= 1.9.0         validate 2.0.3 against git://github.com/components/jquery.git#>= 1.9.0
bower jquery#~2.0.3            install jquery#2.0.3

jquery#2.0.3 bower_components\jquery

~ D:\workspace\javascript\nodejs-bower>bower list
bower check-new     Checking for new versions of the project dependencies..
nodejs-bower#0.0.0 D:\workspace\javascript\nodejs-bower
├─┬ bootstrap#3.0.0-rc1 extraneous
│ └── jquery#2.0.3
├── d3#3.2.8
└── jquery#2.0.3

多么智能,一键搞定,这才是高效的开发。

###7). 查看本地bower已经缓存的类库

~ D:\workspace\javascript\nodejs-bower>bower cache list
bootstrap=git://github.com/twbs/bootstrap.git#3.0.0-rc1
d3=git://github.com/mbostock/d3.git#3.2.8
jquery=git://github.com/components/jquery.git#1.7.2
jquery=git://github.com/components/jquery.git#2.0.3

###8). 查看D3库信息

~ D:\workspace\javascript\nodejs-bower>bower info d3
d3

  Versions:
    + 3.2.8
    + 3.2.7
    + 3.2.6
    + 3.2.5
    + 3.2.4
    + 3.2.3
    ...

###9). 查看dojo库的url

~ D:\workspace\javascript\nodejs-bower>bower lookup dojo
dojo git://github.com/dojo/dojo.git

###10). 用浏览器打开dojo的发布主页

~ D:\workspace\javascript\nodejs-bower>bower home dojo
bower dojo#*                not-cached git://github.com/dojo/dojo.git#*
bower dojo#*                   resolve git://github.com/dojo/dojo.git#*
bower dojo#*                  download https://github.com/dojo/dojo/archive/1.9.1.tar.gz
bower dojo#*                   extract archive.tar.gz
bower dojo#*                  resolved git://github.com/dojo/dojo.git#1.9.1

浏览器自动打开:https://github.com/dojo/dojo

###11). 查询包含dojo的类库

~ D:\workspace\javascript\nodejs-bower>bower search dojo
Search results:

    dojo git://github.com/dojo/dojo.git
    dojox git://github.com/dojo/dojox.git
    dojo-util git://github.com/dojo/util.git
    dojo-bootstrap git://github.com/samvdb/Dojo-Bootstrap

真是方便实用的技术。

##5. 用bower提交自己类库

###1). 生成bower.json配置文件

~ D:\workspace\javascript\nodejs-bower>bower init
bower existing      The existing bower.json file will be used and filled in
[?] name: nodejs-bower
[?] version: 0.0.0
[?] main file:
[?] set currently installed components as dependencies? No
[?] add commonly ignored files to ignore list? Yes

查看生成的文件bower.json

{
  "name": "nodejs-bower",
  "version": "0.0.0",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "d3": "git://github.com/mbostock/d3.git#~3.2.8",
    "jquery": "git://github.com/components/jquery.git#~2.0.3"
  }
}

###2). 在github创建一个资源库:nodejs-bower

###3). 本地工程绑定github

~ D:\workspace\javascript\nodejs-bower>git init
Initialized empty Git repository in D:/workspace/javascript/nodejs-bower/.git/

~ D:\workspace\javascript\nodejs-bower>git add .
~ D:\workspace\javascript\nodejs-bower>git commit -m "first commit"
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#       app.js
#       bower.json
#       bower_components/
#       node_modules/
#       package.json
#       public/
#       routes/
#       views/
nothing added to commit but untracked files present (use "git add" to track)

~ D:\workspace\javascript\nodejs-bower>git remote add origin https://github.com/bsspirit/nodejs-bower

~ D:\workspace\javascript\nodejs-bower>git push -u origin master
Counting objects: 565, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (516/516), done.
Writing objects: 100% (565/565), 803.08 KiB, done.
Total 565 (delta 26), reused 0 (delta 0)
To https://github.com/bsspirit/nodejs-bower
 - [new branch]      master -> master
Branch master set up to track remote branch master from origin.

###4). 注册到bower官方类库

~ D:\workspace\javascript\nodejs-bower>bower register nodejs-bower git@github.com:bsspirit/nodejs-bower.git
bower                          convert Converted git@github.com:bsspirit/nodejs-bower.git to git://github.com/bsspirit/n
odejs-bower.git
bower nodejs-bower#*           resolve git://github.com/bsspirit/nodejs-bower.git#*
bower nodejs-bower#*          checkout master
bower nodejs-bower#*          resolved git://github.com/bsspirit/nodejs-bower.git#af3ceaac07
Registering a package will make it visible and installable via the registry (https://bower.herokuapp.com), continue? (y/
n)                    y
bower nodejs-bower            register git://github.com/bsspirit/nodejs-bower.git

Package nodejs-bower registered successfully!
All valid semver tags on git://github.com/bsspirit/nodejs-bower.git will be available as versions.
To publish a new version, you just need release a valid semver tag.

Run bower info nodejs-bower to list the package versions.

###5). 查询我们自己的包

D:\workspace\javascript\nodejs-bower>bower search nodejs-bower
Search results:

    nodejs-bower git://github.com/bsspirit/nodejs-bower.git

###6). 安装我们自己的包

D:\workspace\javascript\nodejs-bower>bower install nodejs-bower
bower nodejs-bower#*            cached git://github.com/bsspirit/nodejs-bower.git#af3ceaac07
bower nodejs-bower#*          validate af3ceaac07 against git://github.com/bsspirit/nodejs-bower.git#*
bower nodejs-bower#*           install nodejs-bower#af3ceaac07

nodejs-bower#af3ceaac07 bower_components\nodejs-bower
├── d3#3.2.8
└── jquery#2.0.3

其实模块化,版本依赖,开发类库,发布类库,安装类库,都是一条命令!还能再简单一点么!快把项目模块化,然后分享给大家吧!!未来是属于开发者的。

node_redis 可让你在 Node.js 编程环境中连接并操作 Redis 上的数据。
简单例子

var redis = require("redis"),
    client = redis.createClient();

client.on("error", function (err) {
    console.log("Error " + err);
});

client.set("string key", "string val", redis.print);
client.hset("hash key", "hashtest 1", "some value", redis.print);
client.hset(["hash key", "hashtest 2", "some other value"], redis.print);
client.hkeys("hash key", function (err, replies) {
    console.log(replies.length + " replies:");
    replies.forEach(function (reply, i) {
        console.log("    " + i + ": " + reply);
    });
    client.quit();
});

Node.js 受益于它的事件驱动和异步的特征,已经很快了。但是,在现代网络中只是快是不行的。如果你打算用 Node.js 开发你的下一个Web 应用的话,那么你就应该无所不用其极,让你的应用更快,异常的快。本文将介绍 10 条,经过检验得知可大大提高 Node 应用的技巧。废话不多说,让我们逐条来看看。

##1. 并行

创建 Web 应用的时候,你可能要多次调用内部 API 来获取各种数据。比如说,假设在 Dashboard 页面上,你要执行下面这几个调用:

用户信息 -getUserProfile().
当前活动 -getRecentActivity().
订阅内容 -getSubscriptions().
通知内容 -getNotifications().
为了拿到这些信息,你应该会为每个方法创建独立的中间件,然后将它们链接到 Dashboard 路由上。不过问题是,这些方法的执行是线性的,上一个没结束之前下一个不会开始。可行解决案是并行调用它们。

如你所知由于异步性,Node.js 非常擅长并行调用多个方法。我们不能暴殄天物。我上面提到的那些方法没有依赖性,所以我们可以并行执行它们。这样我们可以削减中间件数量,大幅提高速度。

我们可以用 async.js 来处理并行,它是一个专门用来调教 JavaScript 异步的 Node 模块。下面代码演示怎样用 async.js 并行调用多个方法的:

function runInParallel() {
  async.parallel([
    getUserProfile,
    getRecentActivity,
    getSubscriptions,
    getNotifications
  ], function(err, results) {
    //This callback runs when all the functions complete
  });
}

如果你想更深入了解 async.js ,请移步它的 GitHub https://github.com/caolan/async 页面。

##2. 异步

根据设计 Node.js 是单线程的。基于这点,同步代码会堵塞整个应用。比如说,多数的文件系统 API 都有它们的同步版本。下面代码演示了文件读取的同步和异步两种操作:

// Asynchronous
fs.readFile('file.txt', function(err, buffer) {
  var content = buffer.toString();
});

// Synchronous
var content = fs.readFileSync('file.txt').toString();

不过要是你执行那种长时间的阻塞操作,主线程就会被阻塞到这些操作完成为止。这大大降低你应用的性能。所以,最好确保你的代码里用的都是异步版本 API,最起码你应该在性能节点异步。而且,你在选用第三方模块的时候也要很小心。因为当你想方设法把同步操作从你代码中剔除之后,一个外部库的同步调用会让你前功尽弃,降低你的应用性能。

##3. 缓存

如果你用到一些不经常变化的数据,你应该把它们缓存起来,改善性能。比如说,下面的代码是获取最新帖子并显示的例子:

var router = express.Router();

router.route('/latestPosts').get(function(req, res) {
  Post.getLatest(function(err, posts) {
    if (err) {
      throw err;
    }

    res.render('posts', { posts: posts });
  });
});

如果你不经常发贴的话,你可以把帖子列表缓存起来,然后一段时间之后再把它们清理掉。比如,我们可以用 Redis 模块来达到这个目的。当然,你必须在你的服务器上装 Redis。然后你可以用叫做 node_redis 的客户端来保存键/值对。下面的例子演示我们怎么缓存帖子:

var redis = require('redis'),
    client = redis.createClient(null, null, { detect_buffers: true }),
    router = express.Router();

router.route('/latestPosts').get(function(req,res){
  client.get('posts', function (err, posts) {
    if (posts) {
      return res.render('posts', { posts: JSON.parse(posts) });
    }

    Post.getLatest(function(err, posts) {
      if (err) {
        throw err;
      }

      client.set('posts', JSON.stringify(posts));    
      res.render('posts', { posts: posts });
    });
  });
});

看到了吧,我们首先检查 Redis 缓存,看看是否有帖子。如果有,我们从缓存中拿这些帖子列表。否则我们就检索数据库内容,然后把结果缓存。此外,一定时间之后,我们可以清理 Redis 缓存,这样就可以更新内容了。

##4. gzip 压缩

开启 gzip 压缩对你的 Web 应用会产生巨大影响。当一个 gzip 压缩浏览器请求某些资源的时候,服务器会在响应返回给浏览器之前进行压缩。如果你不用 gzip 压缩你的静态资源,浏览器拿到它们可能会花费更长时间。

在 Express 应用中,我们可以用内建 express.static() 中间件来处理静态内容。此外,还可以用 compression 中间件压缩和处理静态内容。下面是使用例:

var compression = require('compression');

app.use(compression()); //use compression 
app.use(express.static(path.join(__dirname, 'public')));

##5. 如果可以,在用客户端渲染

现在有超多功能强劲的客户端 MVC/MVVM 框架,比如说 AngularJS, Ember, Meteor, 等等,构建一个单页面应用变得非常简单。基本上,你只要公开一个 API,返回 JSON 响应给客户端就可以了,而不需要在服务端渲染页面。在客户端,你可以用框架来组织 JSON 然后把它们显示在 UI 上。服务端只发送 JSON 响应可以节省带宽,改善性能,因为你不需要在每个响应里面都返回布局标记了,对吧,你只需要返回纯 JSON,然后在客户端渲染它们。

看下我的这个教程,它是关于怎样用 Express 4 公开一个 RESTful APIs的。我还写了另一篇教程,演示了怎样把这些 APIs 和 AngularJS 结合起来。

##6. 不要在 Sessions 存储太多数据

典型的 Express 页面应用, Session 数据默认是保存在内存中的。当你把太多数据保存在 Session 的时候,会导致服务器开销显著增大。所以,要么你切换到别的储存方式来保存 Session 数据,要么尽量减少存储在 Session 中的数据量。

比如说,当用户登录到你的应用的时候,你可以只在 Session 中保存他们的 ID 而不是整个用户数据对象。还有,对于那些你能够从 id 拿到对象的查询,你应该会喜欢用 MongoDB 或者 Redis 来存储 session 数据。

##7. 优化查询

假设你有个博客,你要在主页上显示最新帖子。你可能会通过 Mongoose 这样取数据:

Post.find().limit(10).exec(function(err, posts) {
  //send posts to client
});

不过问题是 Mongoose 的 find() 方法会把对象的所有字段都查询出来,而许多字段在主页上并不要求。比如说,commentsis 保存的是特定帖子的回复。我们不需要显示文章回复,所以我们可以在查询的时候把它给剔除掉。这无疑会提高速度。可以像这样优化上面那条查询:

Post.find().limit(10).exclude('comments').exec(function(err, posts) {
  //send posts to client
});

##8. 用标准的 V8 方法

集合上的一些操作,比如 map,reduce,和 forEach 不一定支持所有浏览器。我们可以通过前台的库解决部分浏览器兼容性问题。但对于 Node.js,你要确切知道 Google 的 V8 JavaScript 引擎支持哪些操作。这样,你就可以在服务端直接用这些内建方法来操作集合了。

##9. 在 Node 前面用 Nginx

Nginx 是个微小型轻量 Web 服务器,用它可以降低你的 Node.js 服务器的负载。你可以把静态资源配置到 nginx 上,而不是在 Node 上。你可以在 nginx 上用 gzip 压缩响应,让所有的响应都变得更小。所以,如果你有个正在营运的产品,我觉得你应该会想用 nginx 来改善运行速度的。

##10. 打包 JavaScript

最后,你还可以大大提高页面应用速度,通过把多个 JS 文件打包。当浏览器在页面渲染中碰到 脚本 元素的时候会被堵塞,直到拿到这个脚本才继续运行(除非设置了异步属性)。比如,如果你的页面有五个 JavaScript 文件,浏览器会发出五个独立的 HTTP 请求来获取他们。如果把这五个文件压缩打包成一个,整体性能将可以大幅提升。CSS 文件也是一样。你可以用诸如 Grunt/Gulp 这样的编译工具来打包你的资源文件。

Express 内部使用 debug 模块来输出日志信息,包括路由匹配和程序运行状况。 如果想看到这些信息,可以在运行你的程序时设置 DEBUG 环境变量为 express:* ,当启动你的程序时,调试信息将输出到控制台上。

$ DEBUG=express:* node ./app.js

使用上面的方式运行 hello world 的例子,将会输出下面的内容

express:application booting in development mode +0ms
express:router defined get /hello.txt +0ms
express:router defined get /hello.txt +1ms

另外,由 express (生成器)生成的应用也使用到了 debug 模块,并且默认被限制在了 my-application 命名空间内。

你可以通过以下命令开启 debug 信息输出:

$ DEBUG=my-application node ./bin/www