月盾的博客

TypeScript中的装饰器Decorato什么时候执行?

月盾

ES6引入了类的概念,同时也引入了类似于java的注解概念,我们称之为装饰器,用于在某些场景下修改类和类成员。typescript要支持装饰器需要手动开启experimentalDecorators

命令行编译

tsc --target ES5 --experimentalDecorators /test.ts 或者配置文件设置:

tsconfig.json:

{
    "compilerOptions": {
        "experimentalDecorators": true
    }
}

那么这个装饰器到底什么原理呢?它是什么时候执行的?用下面代码为例:

//test.ts
class Route {
    greeting: string;
    constructor(greet: string){
        this.greeting = greet;
    }

    @route("hello")
    default(): any {
        console.log(this.greeting);
    }
}

function route(name: string) {
    return function (target: Object, value: string, desc: PropertyDescriptor) {
        console.log('>>>>', name);
    }
} 

生成的js代码:

//test.js
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var Route = /** @class */ (function () {
    function Route(greet) {
        this.greeting = greet;
    }
    Route.prototype.default = function () {
        console.log(this.greeting);
    };
    __decorate([
        route("hello")
    ], Route.prototype, "default", null);
    return Route;
}());
function route(name) {
    return function (target, value, desc) {
        console.log('装饰器输出', name);
    };
}

备注

使用typescript开发nodejs的环境搭建(一)

月盾

在一切开始之前先具备的开发环境:

  • nodejs4.0+

  • 推荐的开发工具vscode

我希望通过本文介绍能直接做出一个最简单的项目框架,以便日后参考,这也是我想把之前纯nodejs写的博用typescript客重写一遍。

还是以expressjs为框架来搭建

使用express-generator来生成项目基本框架,需要全局安装

npm install -g express-generator

express -e mpro

参数-e是以ejs为模板引擎,mpor为项目目录名,最后生成这样的目录结构:

. 
├── app.js 
├── bin 
│ └── www 
├── package.json 
├── public 
│ ├── images 
│ ├── javascripts 
│ └── stylesheets 
│ └── style.css 
├── routes 
│ ├── index.js 
│ └── users.js 
└── views 
├── error.ejs 
└── index.ejs 

然后是全局安装typescript,便于在任何目录下编译,也可以安装在项目目录下。

npm install -g typescript

安装完以后初始化typescript:

tsc –init

会在根目录下生成tsconfig.json文件,用于配置ts的编译选项。 有了基本目录以后就可以着手编写代码了,为了使用ts开发,可以手动将routes目录下的js文件 和app.js后缀名改成.ts. 做完以上步骤以后可以试着在项目根目录下执行> tsc命令,可能什么都没发生, 这个命令会默认编译当前目录下的ts文件,但是我们项目中并没有这样的文件, 你可以自己新建一个后缀为.ts的文件再执行> tsc还是什么都没有发生一样,但是如果我们把app.ts (已经改过后缀的app.js文件)中的

使用半年TypeScript后的感受

月盾

初识TypeScript

从入职新公司开始算,使用typescript已经有半年多了,这是一个创业公司使用nodejs开发的后台业务管理系统,已经做的很大了,支撑着公司每月千万人民币的业务处理。很多怀疑nodejs是否可以开发后台管理,作为一个过来人告诉你可以放心使用,现在的javascript早已不是10年前用来写前端特效的js了。美中不足的是nodejs对报表这类数据处理量较大的功能有点力不从心,经常拖垮系统,当然也不是完全不能用nodejs来处理报表,可以合理的使用子进程单独处理数据而不影响主进程。但还是不推荐。

使用感受

其实起初对于typescript开发nodejs我是拒绝的,原因是建立起这个项目的人都走了,而这个项目结构实在是复杂,在windows下环境搭建费了好大精力,尤其是为了使用一个bcrypt加密包,需要安装Python,C++来编译,还不能使用nodejs0.12以上版本,最烦人的是每次修改文件后编译速度非常慢,这让我重新体验了开发JAVA时期的痛苦。而且服务启动方法也是前人自己编写shell脚本来同时编译前端文件和后端文件。并没有使用nodemon,supervisor这种监控工具。后来折腾发现可以直接使用vscode单独编译ts文件,一般12秒就编译完成,这与我之前的项目1秒修改重启相比还是慢了很多,不过也免强只能接受,此时只觉得如此麻烦和JAVA开发有什么区别!所以基于这些不好的体验我很不喜欢typescript。

重新认识

最近又折腾了下我用纯nodejs开发的博客,突然发现,写起来确实不如typescript爽,主要是纯nodejs在webstorm和vscode上语法提示和错误提示较弱,而typescript则可以很好的提示并且在开发过程中就能发现一些很低级错误,不用等到运行时才发现。尤其是对ES6的支持比较完整,甚至可以使用async,await这些ES7提案中的特性。虽然现在高版本的nodejs已经支持一些新特性,但是并不是所有项目都可以使用高版本。如果说为什么要使用typescript,那就是typescript集合了js的快速和强类型语言的安全稳定,用于开发一些较大的项目绝对利大于弊。 尤其是对于一些多人合作的项目来说,typescript的强类型能够很好约束对象属性,参数传递,对后续的重构也起到至关重要的作用。 有人可能会担心降低开发效率,这一点大可不必担心,你定义类型消耗的时间会从强类型提示上补回来的。 接下来会写一篇完整的环境搭建教程:使用typescript开发nodejs的环境搭建(一)

beego post请求获取request body参数

月盾

为了获取json类型的参数煞费苦心,差点不再爱了。

前端请求代码:

$.ajax({
    url: "/user",
    type: "post",
    contentType: 'application/json',
    data: JSON.stringify({username:"张三",mobile:"13265478965"}),
    //这才是最重要的地方,必须用JSON.stringify序列化成字符串,
    //直接使用对象死活都接收不到,至于大小写并不影响,只要写对了就行
    dataType: "json"
}).done(function(res) {
    if(res.result){
        alert("成功")
    }
});

需要传输json类型数据,同时数据需要使用JSON.stringify序列化。

后端接收代码:

func (c *UserController) Post() {
    var form struct {
		Username string `json:"username"`
		Mobile   string `json:"mobile"`
	}
	c.BindJSON(&form)
    user := &User{Username: form.UserName, Mobile: form.Mobile}
    err := user.AddUser()//这是添加用户函数
    if nil != err {
        c.Data["json"] = map[string]interface{}{"result": false, "msg": err}
    } else {
        c.Data["json"] = map[string]interface{}{"result": true, "msg": "新增成功"}
    }
    c.ServeJSON()
}

可以使用beego提供的BindJSON函数解析json数据。

特别注意: 如果数据类型不匹配也会造成空数据结果。 例如:前端参数是age: "23",model中age int,也会获取不到数据。

把公司电脑拿回家用

月盾

每个上班的人都会有这样的情况:在公司写一篇文档,设计一份PPT,但是此时已经下班了,又不想继续待在公司做,想拿回家做,所以只能将正在做的文件拷到U盘带回家,或保存到网络硬盘里,回家以后再打开自己的电脑插上U盘打开文件,做完以后再拷到U盘,说不定第二天还忘记带U盘,到了公司还得重做。

基于以上情况,目前想到的有两种解决方案:
第一种,在公司和家里的电脑上分别安装teamviewer软件,登录注册添加远程计算机,回家以后不需要再携带U盘,打开自己的电脑可以直接远程公司电脑工作。

第二种,虽然第一种方法省去了带U盘的麻烦,但还是要开自己的电脑远程连接才行,也没省多少事。终究还是要开自己的电脑才能开始工作,而且远程连接的体验也不是很好,屏幕分辨率不一致导致显示效果不一样,尤其是字体会放大缩小。如果有条件的话何不在家里配一台大屏幕的显示器。而且你买一台三五千的笔记本就看看电影之类的小事情那就大才小用了,也根本没必要。所以我们何不将公司的电脑当做自己拿回来用呢!我的意思不是真的将公司的电脑扛回来用,而是用公司的电脑主机,家里只需要显示器,鼠键即可。要实现这样的需求要借助目前一些现成的解决方案。

比如http://www.yun0101.com/xnhcp/nc61.html这样的设备,或者以前一家公司使用过的华为云终端。只需要一个小盒子即可连接云主机。第二种方案是我想要的,但是还没有亲自实现,需要继续探究去实现。

nodejs请求网络资源写到本地

月盾

nodejs请求网络资源写到本地

有这样一个需求:抓取网络上的图片或其他类型文件保存的本地,根据以往的经验这样写:

var request=require("request");
var fs=require("fs");

var url="http://h.hiphotos.baidu.com/zhidao/pic/item/6d81800a19d8bc3ed69473cb848ba61ea8d34516.jpg";
HttpRequest.get(url, (err, res, body) => {
    res.setEncoding("binary");//二进制(binary)
    FS.writeFile("out.png", body, "binary", function (err) {//以二进制格式保存
        if (err) throw err;
        console.log("file saved");
    });
});

这个例子可能看起来比较眼熟,其实我就是从网上找来的,如果用这种方法成功的话那么恭喜你了,反正我是没有成功。还有一种情况是虽然成功的写文件到本地了,但是打不开,反正提示就是文件损坏之类的。总之,就是上面的方法行……不……通……

还好,有另一种方法可行,而且看起来代码量也少了很多。

var url="http://h.hiphotos.baidu.com/zhidao/pic/item/6d81800a19d8bc3ed69473cb848ba61ea8d34516.jpg";
request(url).pipe(fs.createWriteStream("out.png"));

不过,虽然代码少了很多,但是疑问多了很多,pipe函数是什么东西,还有fs.createWriteStream()函数,借助nodejs帮助文档大概解释一二。
_pipe_函数把他称作为管道吧,回头看一下代码,就是把前面请求的内容通过管道输送到后面的容器里面。虽然这么说还是不太理解,为什么可以调用pipe管道?

非郑重声明:本人也是用蹩脚的英语大概理解nodejs stream的相关知识,如果有不妥的地方误导了人只能表示抱歉

有关网络请求,比如http request,和文件操作方面的都涉及到流的概念,流是可读可写的,

const http = require("http");

var server = http.createServer( (req, res) => {

}

其中req是可读Readable Stream的流,res是可写Writable Stream的流,再看request(url).pipe(fs.createWriteStream("out.png"));,
request是继承自stream模块的,所以它也是具有可读可写的特性,自然就能调用pipe函数,从而获取到数据,然后需要写入到一个文件中,就需要由pipe输出到一个可写的流中,fs.createWriteStream(path)返回一个可写WriteStream的流,就可以接受pipe管道的输出,最后写入到本地文件。

iphone快速锁屏

月盾

以iphone5s来说明,要关闭屏幕通常需要按顶部电源键,但是iphone5s的电源键高度太低,如果再装个手机壳的话基本很难按到,或者需要很大的力气才能锁屏。而且长期按压也会按坏,就算现在没坏也有这样的担心不是吗?所以我们希望有个快捷方式点击屏幕就能锁屏,所幸iphone提供了这样的功能,不过默认没有放到第一级菜单中,所以不太好找,但是可以通过设置来放到第一级菜单,就是屏幕上的虚拟home键打开后的菜单。

设置-通用-辅助功能-AssistiveTouch-自定顶层菜单,点击一个不常用的按钮,选择锁定屏幕,完成。

使用scp在Windows和linux之间传输文件

月盾

获取远程服务器(linux)文件到本地(Windows): scp 远程name@远程IP:远程文件 本地文件
发送本地文件(Windows)到远程服务器(linux): scp 本地文件名 远程name@远程IP地址**:远程文件**

nodejs中vm模块的作用

月盾

vm提供了一个沙箱环境,什么叫沙箱环境?类似于一个独立的执行空间,什么时候会用到vm模块?就以我现在接触的需求来说,每个月都有运营活动,但是每次需求又不同,比如一些优惠规则不同,最后可能只需要得到一个结果,如果每次活动都去修改代码就会显得很麻烦,我们提供一个后台管理界面,或者直接在数据库里写入每次活动的不同计算规则,这些规则其实也是JavaScript代码,既然是代码就需要执行才行。这就形成了一种情况:在已有的程序中插入一段代码进行执行,这要怎么实现?如果觉得很容易插入的话,那么是不是黑客可以在你的程序中插入一段代码执行呢?这当然是不允许的,所以就需要提供一种安全环境来执行——就是沙箱了,而vm模块就是提供了这样一种执行环境。 http://www.cnblogs.com/softlover/archive/2012/10/03/2707144.html