0%

来龙去脉

在用less+gulp开发时,有时候代码还没写完整,不小心保存了一下,然后gulp就开始执行gulp-less的task。
但是代码是有问题的,这时候会输出一个Potentially unhandled rejection,告诉你哪里出问题了,然后,
然后就挂了!!pipe就会停止输入数据,整个task就停止了。
特别是我用Sublime,设置了失去焦点自动保存,很容易出现这个问题。

解决办法

gulp-plumber插件解决了这个问题。
插件作者的想法 Error management in gulp

使用方法:

先npm下载下来

1
npm install gulp-plumber --save-dev

在gulpfile.js中,引入gulp-plumber,然后在处理less的task中加上:

1
2
3
4
5
6
7
8
9
var plumber = require('gulp-plumber');

gulp.task('less', function(){
return gulp.src('./less/*.less')
.pipe(plumber()) //加上这句
.pipe(less())
.pipe(gulp.dest('./css'))
.pipe(browserSync.stream());
});

参考

阅读全文 »

之前我用nodemailer通过163邮箱来发送邮件,不过没过几天就一直ETIMEDOUT,不知道什么原因,想着还是自己搭一个来发邮件可能靠谱点(flag?)

安装postfix

CentOS 7 自带了postfix服务,在/etc/postfix 目录下

没有安装的可以用yum安装

为域名添加DNS解析

需要添加三条记录,A记录、MX记录、TXT记录

配置postfix

我接触postfix的时候貌似已经被人玩烂了,网上一搜几年前的文章一大把。

有关域名解析、postfix配置跟使用telnet测试发送邮件,可以参照这篇文章,亲测。

阿里云CentOS Linux服务器上用postfix搭建邮件服务器

阅读全文 »

本文讲的是用Node.js通过一个开启smtp的已有的邮箱账号发送邮件,而不是如何创建一个邮件服务器

开启smtp服务

首先要去要使用的邮箱中设置开启smtp,才能正常发送邮件

这边以163邮箱为例

163mail set smtp

安装Nodemailer模块

1
npm install nodemailer --save-dev

设置Nodemailer

1
2
3
4
5
6
7
8
9
10
11
var nodemailer = require('nodemailer');

//username替换为邮箱名,%40后面是邮件服务器的地址,比如163.com,password替换为邮箱密码(或独立密码,如果有设置的话),@后面填SMTP服务器地址,如163的smtp地址为smtp.163.com
var transport = nodemailer.createTransport('smtps://username%40163.com:password@smtp.163.com');
var mailOptions = {
from: 'example@163.com', //发件人
to: 'abc@163.com, def@163.com', //收件人,可以设置多个
subject: '', //邮件主题
text: '', //邮件文本
html: '' //html格式文本
};

发送邮件

阅读全文 »

MongoDB(名称取自“huMONGOus“)是一个有着全面灵活的索引支持和丰富的查询的数据库。MongoDB通过GridFS提供强大的媒体存储。点击这里获取MongoDB的更多信息

MongoDB发布了一个新的稳定版本 3.2,进行了大量的改进。本教程将帮助你在CentOS, RHEL 和 Fedora 系统上安装MongoDB 3.2.X

第一步 —— 将MongoDB添加到yum仓库

将下列内容按照你需要的MongoDB版本和系统架构添加到yum仓库的配置文件/etc/yum.repos.d/mongodb.repo中。在本文中我们使用MongoDB 3.2的仓库。

64位系统使用:

1
2
3
4
5
[MongoDB]
name=MongoDB Repository
baseurl=http://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.2/x86_64/
gpgcheck=0
enabled=1

第二步 —— 安装MongoDB服务器

使用yum包管理器安装mongodb-org包,这个操作会自动安装所有的依赖。若要安装具体的MongoDB修订版,只要指定包的名称,带上版本号,例如mongodb-org-3.2.0。以下命令会安装最新可用的稳定版。

1
# yum install mongodb-org

第三步 —— 启动MongoDB

阅读全文 »

前几天四六级成绩出来(然而我没考),用Node.js做了一个模拟表单提交并抓取数据的Web
总结一下用到的知识,简单的网页抓取大概就是这个流程了

发送Get或Post请求

表单提交,首先弄到原网页提交的地址,然后引入http或https模块
也可以下载使用request模块。
这边以get为例

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
31
32
33
34
35
var http = require('http');

//设置请求参数,包括headers
var options = {
url: 'www.chsi.com.cn',
encoding: null,
host: 'www.chsi.com.cn',
path: '/cet/query?' + querystring,
method: 'GET',
headers: {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, sdch',
'Accept-Language': 'zh-CN,zh;q=0.8',
'Connection': 'keep-alive',
'Cookie': 'JSESSIONID=8D79F004CB79FC5352F123F76CF4D853; __utmt=1; __utma=65168252.1576213452.1471513579.1471575867.1471575870.3; __utmb=65168252.5.10.1471575870; __utmc=65168252; __utmz=65168252.1471575870.3.3.utmcsr=baidu|utmccn=(organic)|utmcmd=organic|utmctr=%E5%AD%A6%E4%BF%A1%E7%BD%91',
'Host': 'www.chsi.com.cn',
'Referer': 'http://www.chsi.com.cn/cet/',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
};

var req = http.request(options, function(res){
res.on('data', function(data){
//处理data事件,当接收到数据时触发
}).on('end', function(){
//处理读取完所有数据的事件
}).on('error', function(err){
//处理错误时的事件
console.log(err);
});
});

//发送请求
req.end();

如果是post请求,需要在req.end()之前用req.write(content)写入请求参数

Transfer-Encoding:chunked?

有时候服务器的response header会带有一个Transfer-Encoding,如果是chunked,说明服务器是分段传输数据的
这种情况下,会触发多次res的data事件,因此可以先定义一个变量,然后在data事件处理函数中将接收到的数据拼接起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var req = http.request(options, function(res){
var data = '';
res.on('data', function(chunk){
//处理data事件,当接收到数据时触发
data += chunk;
}).on('end', function(){
//处理读取完所有数据的事件
}).on('error', function(err){
//处理错误时的事件
console.log(err);
});
});

//发送请求
req.end();

使用zlib库解压gzip压缩过的html

现在很多网站在进行数据传输时都会先用gzip或deflate压缩以减小传输数据的体积,这样,我们请求到的数据就是压缩过的数据,无法正常解析,因此需要先解压

阅读全文 »

  • 目录
    {:toc}

写好代码,花钱买了VPS,看着Charges一直上涨却无从下手?记一位新手司机从购买VPS到成功访问的过程

0.购买VPS

首先,选择VPS提供商,部署一个新的服务器(Deploy New Server),我使用的是Vultr提供的VPS
操作系统可以自由选择,我这边使用的是CentOS 7,选择其他操作系统的胖友可以搜一下相应操作系统的部署教程

1.使用PuTTY连接远程VPS

安装PuTTY

打开PuTTY,在 Host Name(or IP address) 那一栏填上VPS提供商给你的IP地址,然后点Open开启一个新会话(也可以点底下的Save保存一下,下次直接双击Saved Sessions中保存的的会话打开就行,无须输入IP)

PuTTY interface

打开后会出现一个Terminal,显示login as: ,这边输入VPS提供商给你的Username,默认应该是root

然后出现root@your ip address ‘s password: ,输入VPS提供商提供的Password(可以在本机上复制,然后在窗口中点击鼠标右键,复制的内容就被粘贴了),然后回车
注意:输入密码的时候不会显示你输入的东西

阅读全文 »

什么是CORS

CORS(Cross-origin resource sharing),跨域资源共享,是一份浏览器技术的规范,用来避开浏览器的同源策略

简单来说就是解决跨域问题的除了jsonp外的另一种方法

CORS的wiki

如何使用CORS

只要服务端在响应时发送一个响应的标头即可

浏览器端还是照常使用ajax,支持get,post

在Node.js上启用CORS

参照StackOverflow上面的一个回答,定义一个中间件来添加响应标头,然后在处理app.get(或post等)之前使用
(这位老兄告诉我们要善用next啊)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//CORS middleware
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://example.com');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');

next();
}

//...
app.configure(function() {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: 'cool beans' }));
app.use(express.methodOverride());
app.use(allowCrossDomain);
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
阅读全文 »

这两天折腾mongoose,发现数据成功写入集合了,但是在Terminal查询的时候却查不到
于是show collections后发现在原来的集合底下,又生成了一个加了s的集合,shenmegui

查了一下,发现是mongoose.model()的问题

Mongoose#model(name, [schema], [collection], [skipInit])

在官方的api文档里面有解释(我不听)

When no collection argument is passed, Mongoose produces a collection name by passing the model name to the utils.toCollectionName method. This method pluralizes the name. If you don’t like this behavior, either pass a collection name or set your schemas collection name option.

当没有传入collection参数时,Mongoose会通过model name(就是第一个参数),调用utils.toCollectionName方法产生一个collection name,而这个方法会使name变成复数形式。如果你不想要这个过程,只要传入collection name参数或设置Schema中的collection name选项。

就像这样:

1
2
3
4
5
6
7
8
9
10
var schema = new Schema({ name: String }, { collection: 'actor' });

// or

schema.set('collection', 'actor');

// or

var collectionName = 'actor'
var M = mongoose.model('Actor', schema, collectionName);

什么坑爹设定…

参考

阅读全文 »

Promise的概念

Promise 对象用于异步(asynchronous)计算.。一个Promise对象代表着一个还未完成,但预期将来会完成的操作。

Promise的几种状态:

  • pending:初始状态,即等待操作的执行
  • fulfilled:成功的操作
  • rejected:失败的操作

pending的状态既可以转为fulfilled,也可以转为rejected,当状态发生改变时,promise.then(onFulfilled, onRejected)方法将被调用

Promise的基本用法

1.首先创建一个Promise的实例

1
2
3
4
5
6
7
8
var promise = new Promise(function(resolve, reject){
//do something
if(success){
resolve(value);
} else {
reject(value);
}
});

构造函数的参数Function中带有两个函数对象resolve和reject,二者都是返回一个Promise对象

  • resolve用在处理执行成功的场景,Promise从pending转为fulfilled状态时调用
  • reject用在处理执行失败的场景,Promise从pending转为rejected状态时调用
阅读全文 »

  • 目录
    {:toc}

Gulp是什么鬼

Gulp是一种基于node.js的构建工具,有关构建工具的概念请移步什么是构建工具

Gulp的安装及基本使用,可参考[一点| gulp详细入门教程][],写得十分6,通俗易懂

Browsersync又是什么鬼

Browsersync可以让浏览器实时响应所做的文件更改,包括html, js, css, less, sass等,并自动刷新页面
而且可以在多个浏览器、多个设备(PC、平板、手机等)下同时进行调试,是提高开发效率的利器

如何安装使用Browsersync

官网上有各种安装使用方式,这边我用gulp

安装

1.全局安装

阅读全文 »

今天搜索module.exports时看到CNode社区上发的Hack Sparrow一篇相关文章的链接
Node.js Module – exports vs module.exports
一篇5年前的远古巨坟…

网上也有相应的翻译,nodejs中exports与module.exports的区别详细介绍

又看了下CNode上的一篇介绍,exports 和 module.exports 的区别

下面做个总结,感谢CNode社区上@manecocomph的解释,十分直白(在上面那篇文章的评论里)

其实exports跟module.exports初始时指向的是同一个空对象{},因此在exports上添加的属性也会被添加到module.exports上
而在另一个文件中,require的返回值是module.exports,因此当exports跟module.exports不指向同一个对象时,exports中的属性便不会被导出

1
2
3
console.log(exports);  //{}
console.log(module.exports); //{}
console.log(exports === module.exports); //true

rocker.js

1
2
exports.name = 'naive';  //{ name: 'naive' }
module.exports = {}; //{},与exports不再指向同一个对象

app.js

阅读全文 »

BUI

基于jQuery的UI类库,后台系统的框架

  • 统一的UI,基于bootstrap
  • 丰富的控件库
  • 完善的demo
  • 说明全面的API文档
  • 封装好的应用(暂时还没用到

为什么使用BUI

  1. 内部使用多
  2. 专注后台应用
  3. 基于jq,上手快

脚手架

dpl.css
bui.css

jquery
sea.js
config.js

  • 栅格系统默认24列(bootstrap是12列
    1. 固定布局960px
    2. 自适应

CSS样式

阅读全文 »

  • 目录
    {:toc}

Less在CSS语法的基础上进行了扩展,主要包含:

  • Variables(变量)
  • Mixins(混合书写)
  • Nested Rules(嵌套规则)
  • Functions & Operations(功能和操作)
  • Client-side usage(客户端使用)
  • Server-side usage(服务端使用)

使用Less

Server-side usage

npm安装

1
npm install -g less

命令行使用

输出到stdout,直接在控制台显示

1
lessc styles.less
阅读全文 »

stackoverflow上 What is a build tool? 的一个回答

什么是构建工具

构建工具是一个把源代码生成可执行应用程序的过程自动化的程序(例如Android app生成apk)。构建包括编译、连接跟把代码打包成可用的或可执行的形式。

基本上构建的自动化是编写或使一大部分任务自动执行的一个动作,而这些任务则是软件开发者的日常,像是:

  1. 下载依赖
  2. 将源代码编译成二进制代码
  3. 打包生成的二进制代码
  4. 进行单元测试
  5. 部署到生产系统

为什么要使用构建工具或构建自动化

在小型项目中,开发者往往手动调用构建过程,这样在大型的项目中很不实用,在构建过程中难以跟踪什么需要被构建、按照什么顺序构建以及项目中存在哪些依赖。使用自动化工具会使构建过程更为连续。

各种现有构建工具(只列举了部分)

  1. For java - Ant,Maven,Gradle.
  2. For .NET framework - NAnt
  3. c# - MsBuild.

深入阅读

阅读全文 »

有关JavaScript的几种继承方式请移步JavaScript的几种继承方式

原型链的缺陷

SubType.prototype = new SuperType();

这样做的话,SuperType构造函数中的属性也会变成SubType原型中的属性,而我们需要SubType原型只继承SuperType原型
还有一点就是引用类型值属性的共享

寄生组合式继承的理解

为了结合原型链、组合继承和寄生式继承的优点,可以新建一个临时的类temp,temp.prototype指向父类的Prototype,然后创建一个temp实例,并给它加上一个constructor属性
这样,相当于用原型链的方法继承temp,由于temp的构造函数为空,所以只继承了原型上的属性,构造函数上的属性再用call或apply来继承

于是,我们可以把封装继承的函数进行修改,不使用object()或Object.create(),便于理解

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
31
32
//继承原型
function inheritPrototype(subType, superType){ //参数为两个类型的构造函数
var temp = function(){};
temp.prototype = superType.prototype;
var tempInstance = new temp(); //创建temp的实例tempInstance

//给temp的实例tempInstance添加constructor属性,指向subType,虽然不是真的prototype.constructor,但是用来实现继承的效果是我们想要的
tempInstance.constructor = subType;
subType.prototype = tempInstance; //原型链继承
}


function SuperType(name){
this.name = name;
this.colors = [];
}


SuperType.prototype.sayName = function(){};


function SubType(name, age){
//继承构造函数中的属性
SuperType.call(this, name);
this.age = age;
}


inheritPrototype(SubType, SuperType);


SubType.prototype.sayAge = function(){};

寄生组合式继承

不用temp,直接SubType.prototype = SuperType.prototype?

阅读全文 »

有关ECMAScript定义如何获取this请移步ECMAScript中关于如何获取this的定义

绝大多数情况下,函数的调用方式决定了this的取值

全局上下文

1
console.log(this === window);  //true

函数上下文

直接调用

1
2
3
4
5
6
7
function fn(){
return this;
}

fn() === window; //true

//this的值不是由函数调用设定,默认为全局对象

严格模式下增强了安全措施,this关键字禁止指向全局对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function fn(){
"use strict";
return this;
}

fn() === undefined; //true

function f(){
"use strict";
this.a = 1;
}

f();// 报错,this未定义

var fun = new f();

console.log(fun.a); //1

对象方法中的this

阅读全文 »

文章中一些名词的翻译存疑,没有查过正式的中文名称

前面都是具体过程的解释,懒得看可以直接看获取思路

有关this的取值请移步JavaScript笔记——this的取值

获取this的过程

Runtime Semantics: Evaluation

  1. Return ResolveThisBinding();

ResolveThisBinding()

The abstract operation ResolveThisBinding determines the binding of the keyword this using the LexicalEnvironment of the running execution context. ResolveThisBinding performs the following steps:

抽象操作ResolveThisBinding通过running execution context中的LexicalEnvironment(词法环境?)来决定关键字this的绑定,执行以下两个步骤:

  1. Let envRec be GetThisEnvironment(); //获取当前环境
  2. Return envRec.GetThisBinding(); //返回当前环境记录中this的绑定
阅读全文 »