<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>醍醐灌顶</title><link href="https://blog.lonelylty.com/" rel="alternate"></link><link href="https://blog.lonelylty.com/feeds/all.atom.xml" rel="self"></link><id>https://blog.lonelylty.com/</id><updated>2017-01-01T09:57:00+01:00</updated><entry><title>在2016年学JavaScript是一种什么样的体验</title><link href="https://blog.lonelylty.com/articles/2017/01/01/how-it-feels-to-learn-javascript-in-2016/" rel="alternate"></link><published>2017-01-01T09:57:00+01:00</published><updated>2017-01-01T09:57:00+01:00</updated><author><name>nick</name></author><id>tag:blog.lonelylty.com,2017-01-01:/articles/2017/01/01/how-it-feels-to-learn-javascript-in-2016/</id><summary type="html">&lt;p&gt;&lt;strong&gt;嘿，我最近接到一个 Web 项目，不过老实说，我这两年没怎么接触 Web 编程，听说 Web 技术已经发生了一些变化。听说你是这里对新技术最了解的 Web 开发工程师？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;准确地说，我是一名「前端工程师」。不过你算是找对人了。我对今年的技术别提多熟了，前端可视化 …&lt;/em&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;嘿，我最近接到一个 Web 项目，不过老实说，我这两年没怎么接触 Web 编程，听说 Web 技术已经发生了一些变化。听说你是这里对新技术最了解的 Web 开发工程师？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;准确地说，我是一名「前端工程师」。不过你算是找对人了。我对今年的技术别提多熟了，前端可视化、音乐播放器、能踢足球的无人机，你尽管问吧。我刚去 JS 大会和 React 大会逛了一圈，没有什么新技术是我不知道的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;厉害。是这样的，我要开发一个网页，用来展示用户的最新动态。我想我应该通过后端接口获取数据，然后用一个 table 来展示数据，用户可以对数据进行排序。如果服务器上的数据变化了，我还需要更新这个 table。我的思路是用 jQuery 来做。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;可别用 jQuery！现在哪还有人用 jQuery。现在是 2016 年了，你绝对应该用 React。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;哦，好吧，React 是什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;React 是一个非常厉害的库，Facebook 的牛人写的。它能让页面更可控，性能极高，而且使用起来很简单。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;听起来确实不错。我能用 React 展示服务器传来的数据吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;当然可以，你只需要添加两个依赖，一个是 React，一个是 React DOM&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;额，等下，为什么是两个库？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;React 是我说的库，React DOM 是用来操作 DOM 的。因为这些 DOM 是用 JSX 写的，所以需要一个专门的库来操作。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JSX？JSX 是什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;JSX 是对 JS 的扩展，它看起来跟 XML 差不多，可以用来写 HTML，你可以认为 JSX 是一种更优雅的 HTML 写法。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么不用 HTML 了……？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在可是 2016 年啊，没有直接写 HTML 的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;对哦。好吧，加了这两个依赖，是不是就可以开始用 React 了？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;不行哦。你需要添加 Babel，然后才能用 React。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Babel 是另一个库？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;嗯，Babel 是一个转译工具，Babel 能把你写的 JS 转译成任意版本的 JS。你不一定非要用 Babel，但是如果你不用的话，你就只能写 ES5 的语法了。你知道的，现在是 2016 年，你怎么能不使用 ES2016+ 的语法呢？ES2016+ 多么酷啊。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ES5 是啥？ES2016+ 又是啥？我有点晕。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ES5 就是 ECMAScript 5。大部分人都会使用 ES5，因为大部分浏览器都支持 ES5。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ECMAScript 是啥……&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;你晓得的，JS是1995年诞生的，而JS的标准是1999制定出来的。那时候 JavaScript 还叫做 Livescript，只能运行在网景的浏览器里。那时真是混乱的年代，现在好了，我们有了 JS 的 7 个版本的规范。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7 个版本？那 ES5 和 ES2016+ 是？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;分别是第 5 个版本和第 7 个版本。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;诶，那第六个版本呢？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;你说的是 ES6。每个版本都是上一个版本的超集，所以你直接使用最新的 ES2016+ 就好了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;对哦。为什么不用 ES6 呢？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好吧，你可以用 ES6，但是你就用不到 async 和 await 这么酷的语法了。用 ES2016+ 比较好。用 ES6 的话你就只能用 generator 来控制异步任务流了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不知道你在说什么……你说了太多我听不懂的名词了。我只是想从服务器取点数据，我以前用 jQuery 挺好的，从 CDN 引入 jQuery，我就能用 AJAX 获取数据了，现在不能这样做吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大哥，都 2016 年了，没人用 jQuery 好吗。所有人都知道用 jQuery 只会造出「意大利面条」一样的代码（不可维护）&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;好吧，所以我现在要加载三个库才能获取并展示数据。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;对的，其实你可以用「模块管理器」把这三个库「打包」成一个文件。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;哦，什么是模块管理器……&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;不同平台的模块管理器不同啦。前端的模块管理器一般指管理 AMD 或者 CommonJS 模块的东西。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;好……吧，什么是 AMD 和 CommonJS？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是两个定义。我们有很多方式来描述 JS 中多个库或类的交互方式，比如 exports 和 requires。你可以按照 AMD 或者 CommonJS 的 API 来书写 JS，然后用 Browserify 将它们打包。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;听起来很有道理。不过，什么是 Browserify？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是一个工具，用来将 CommonJS 形式的 JS 文件打包起来，放到浏览器里运行。用 npm 仓库的人发明了 CommonJS。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;npm 仓库是什么……&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是一个公开的仓库，用于放置可依赖的模块。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;就像一个 CDN 么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;不太一样。它更像是一个数据库，每个人都能在上面发布代码，也能下载上面的代码。你可以在开发的时候将这些代码下载到本地来使用，必要的时候也能上传到 CDN。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;听起来像是 Bower！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是的，不过现在是 2016 年了，没有人用 Bower 了……&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;好吧，我知道了，所以我应该用 npm 来安装依赖。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;对的。我举个例子吧，如果你要使用 React，你直接用 npm 安装 React，然后在代码里导入 React 就可以了。大部分 JS 库都能这么安装。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;嗯，Angular 也可以。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Angular 是 2015 年的事情了。不过今年 Angular 还没死，还有 VueJS 和 RxJS 等等，你想学一学么？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;还是用 React 吧。我刚才已经学了够多东西了。所以我用 npm 安装 React 然后用 Browerify 来打包就好了？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这么做看起来有点过于复杂啊。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;确实。这就是为什么你应该使用 Grunt、Gulp 或者 Broccoli 这样的任务管理工具，它们能自动运行 Browserify。不对，你现在可以用 Mimosa。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你在说什么……&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;任务管理工具。不过我们现在已经不用了。去年我们还在用，后来改成了 Makefiles，但是现在我们用的都是 Webpack。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我以为只有 C/C++ 项目才会用 Makefiles。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是的，不过显然我们做 Web 开发的，喜欢先把事情搞复杂，然后回归到最朴素的状态。每年我们都是这么搞的。你就看着吧，过不了两年，我们就可以在网页上写汇编了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;唉，你刚才说的 Webpack 是什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一种模块管理工具，同时也是一个任务管理工具。你可以认为它是 Browserify 的加强版。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;哦，好吧，为什么 Webpack 是加强版？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;额，可能并没有加强吧。Webpack 告诉你应该如何管理你的依赖，Webpack 允许你使用不同的模块管理器，不只是 CommonJS，甚至支持 ES6 模块。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这都是哪跟哪啊，我都被绕晕了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家都被绕晕了，不过等 SystemJS 出来了就好了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;天呐，又一个 JS 库，这是什么鬼？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;呵呵，不像 Browserify 和 Webpack 1.x，SystemJS 是一个动态的模块加载器。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;等下，刚才不是说应该把所有依赖打包成一个文件吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;话是这么说，但是等 HTTP/2 普及之后，不打包反而更好。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;那为什么我们不直接在页面里添加 React 的三个依赖文件呢？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;不行。你可以从 CDN 加载这些文件，但是你还是要在本地用 Babel 转译。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;唉，这么鹾？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是的，你不能在生产环境上运行 babel，你应该在发布到生产环境之前，运行一系列的任务，包括压缩、混淆、内联化CSS、延迟加载script……&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我懂了我懂了。既然我不能直接用 CDN，那么我应该怎么做？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我会考虑用 Webpack + SystemJS + Babel 来转译 Typescript。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Typescript？我们不是在说 JavaScript 吗？！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Typescript 也是 JavaScript 呀，它比 JS 更好用，是 JS 的超集，它是基于 ES6 的，就是我们刚才谈论的 ES6，你还记得吧。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ES2016+ 已经是 ES6 的超集了，怎么又冒出来一个 Typescript？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是这样的，Typescript 能让我们写出「强类型」的 JS，从而减少运行时的错误。2016年，我们应该让 JS 支持强类型了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;显然 Typescript 可以做到。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Flow 也可以做到，区别是 Typescript 需要编译，而 Flow 只是检查语法。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;唉，Flow 是？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是一个静态类型检查器，就是 Facebook 的人写的。使用 OCaml 写的，函数式编程很叼的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OCaml？函数式编程？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;如今大牛都用这些东西，都2016年了，你懂的，函数式编程、高阶函数、柯里化、纯函数这些概念。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不知道你在说什么。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;一开始大家都不知道。这么说吧，你只需要知道函数式编程比面向对象编程厉害，2016 年我们就指着函数式编程了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;等下，我大学里学过面向对象编程，当时我觉得它还不错。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Java 在被 Oracle 买下来之前也挺不错啊。我的意思是，面向对象以前是不错，现在依然有人用它，但是现在所有人都发觉状态变换是很难维护的，所以大家都开始用「不可变对象」和函数式编程了。Haskell 的人已经用这套东西用了很久了，不过幸运的是 Web 开发领域里有 Ramda 这样的库，让我们用 JS 就可以进行函数式编程了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你刚刚是不是又抛出了几个名词？Ramnda 又是什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;不是 Ramnda，是 Ramda，跟 Lambda 表达式有点像。是 David Chambers 写的库。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;谁？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;David Chambers，大神一个。blablabla&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我不得不打断你一下了。这些东西看起来都不错，但是我觉得它们都太复杂，而且没必要。我只是想获取数据然后展示，我很确定这种情况下我不需要掌握这些知识。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;回到 React 吧，用 React 我怎么从服务器获取数据？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;额，React 没有提供这个功能，你只能用 React 展示数据。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;服了啊。那我怎么获取数据？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;你用 Fetch API 就可以了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;啥玩意？这个 API 的名字很烂啊。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我也觉得是啊。Fetch API 是浏览器提供的异步请求接口。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;哦，那不就是 AJAX。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;AJAX 只是使用 XMLHttpRequest 对象，但是 Fetch API 可以让你用 Promise 风格来发起异步请求，帮你摆脱「回调地狱」。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;回调地狱？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是的，每次你发起一个异步请求，就得等待它响应。这时你就得在函数里使用一个函数，这种嵌套调用就是回调地狱。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;好吧。Promise 解决了这个问题么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是的。用 Promise 来管理回调，你就可以写出更易读的代码，更容易测试的代码。甚至可以同时发起多个请求，然后等待它们全部返回。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fetch 也能做到吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;是的。但前提是你的用户使用了新版的浏览器，不然的话你就需要加一个 Fetch 的 「polyfill」，或者使用 Request、Bluebird 或者 Axios 这些库。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;天呐我到底需要多少个库？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;这是 JS，同一件事情有上千个库在做。我们了解库，而且我们有最好的库，我们有海量的库，要什么有什么。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你刚才说的几个库都是干什么的？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;这几个库操作 XMLHttpRequest 然后返回 Promise 对象。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;好像 jQuery 的 ajax 方法做的是同样的事吧……&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;从 2016 年起我们就不用 jQuery 了。用 Fetch，大不了加个 Polyfill，要不然用 Bluebird、Request 或者 Axios 都行。然后用 await 和 async 管理 Promise，这样才能控制好异步任务。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这是你第三次说 await 了，那是什么东西？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;await 能让你拦住一个异步调用，让你更好地控制异步返回的数据，大大增强了代码的可读性。await 非常好用，你只需要在 Babel 里添加 stage–3 配置，或者添加 syntax-async-functions 和 transform-async-to-generator 插件就可以了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;听起来像是疯了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;没疯。为了使用 await，把 Typescript 编译之后再用 Babel 转译一道的人才是疯了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;啥玩意？Typescript 不支持 await？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;下个版本就支持了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我已经无话可说了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;你看其实很简单。用 Typescript 写代码，用 Fetch 发起异步请求，所有代码编译成 ES6，然后用上 Babel 的 stage–3 配置项，把 ES6 转译成 ES5。所有代码用 SystemJS 加载。如果你用不了 Fetch，就加个 polyfill，或者用 Bluebird、Request 或者 Axios，这样你就可以用 await 来处理 Promise 了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;看来我们俩对于「简单」的理解是不同的。好吧，有了这些，我终于可以获取数据然后用 React 展示数据了，对吧？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;你的网页需要处理状态变更吗？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;唔，不用吧。我只是想展示数据。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;那就好，不然我就得跟你解释 Flux，以及 Flux 的一些实现，比如 Flummox、Alt、Fluxible。不过说真的你应该用 Redux。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你说的这些我就当耳旁风了。再说一次，我只想展示数据。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;这样啊，如果你只是想展示数据，其实你不需要 React。你只需要一个模板引擎。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你逗我呢？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我只是告诉你你可以用什么技术。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;别说了，真的。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我想说，即使只是用一个模板引擎，我还是会用 Typescript + SystemJS + Babel 的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我只是想在页面上展示数据，你就告诉我用哪个模板引擎就好了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;有很多，你用过哪一个？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;额，太久没用了，不记得了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;jTemplates、jQote 还是 PURE？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;额，不记得，还有别的么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Transparency? JSRender? MarkupJS? KnockoutJS? 这一个支持双向绑定。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;还有吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PlatesJS? jQuery-tmpl? Handlebars? 还有些人在用。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;有点像。有哪些跟最后一个比较像的？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Mustache, underscore? 我记得连 Lodash 都有一个模板引擎，不过这是 2014 年的事情了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;额，也许是再新一点的库？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Jade? DustJS？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;没用过&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;DotJS? EJS？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;没用过。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Nunjucks? ECT?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;没用过。记不起来了，要是你的话，你用哪个？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我应该会用 ES6 原生的模板字符串&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我猜猜，只有 ES6 支持。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;对的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需要用 Babel&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;对的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需要用 npm 安装&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;对的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需要用 Browserify 或者 Webpack，或者 SystemJS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;对的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果没用 Webpack 的话，我还需要一个任务管理工具。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;对的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;但是由于我要用函数式编程和强类型语言，所以我首先要用上 Typescript 或者 Flow。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;对的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果我要用 await，那我就必须用 Babel 转译。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;对的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;然后我就能用上 Fetch、Promise 和各种炫酷的东西。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;嗯，别忘了加上 Fetch 的 Polyfill，因为 Safari 不支持 Fetch。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你猜怎么着，我们就聊到这吧。我不做了，我不做 Web 了，我也不想再碰 JS 了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;没事，过不了几年，我们都会用 Elm 或者 WebAssembly 了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我要回后端去了，我受不这些变动、版本更新、编译和转译了，JS 社区如果觉得有人能跟上它的脚步，那这个社区就是疯了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我理解你。我建议你去 Python 社区。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;听说过 Python 3 吗？&lt;/em&gt;&lt;/p&gt;
&lt;div class="div-border-top-blue"&gt;最后一句「听说过 Python 3 吗？」是讽刺 Python 3 发布已经 8 年了，Python 社区却依然在使用 Python 2.7。而 JS 社区正好相反，把还没有实现的语言特性都用到生成环境中了！&lt;/div&gt;

&lt;p&gt;&lt;br/&gt;
&lt;a href="https://hackernoon.com/how-it-feels-to-learn-javascript-in-2016-d3a717dd577f#.7xu075vbl" target="_blank"&gt;原文出处&lt;/a&gt;&lt;/p&gt;</content><category term="javascript"></category></entry><entry><title>网站架构演进</title><link href="https://blog.lonelylty.com/articles/2016/10/07/web-architecture-evolution/" rel="alternate"></link><published>2016-10-07T09:57:00+02:00</published><updated>2016-10-07T09:57:00+02:00</updated><author><name>nick</name></author><id>tag:blog.lonelylty.com,2016-10-07:/articles/2016/10/07/web-architecture-evolution/</id><summary type="html">&lt;p&gt;网站架构的演进不外乎两个原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户越来越多，意味着并发要求越来越高&lt;/li&gt;
&lt;li&gt;数据越来越多，意味着存储挑战越来越大&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;上古时代&lt;/h4&gt;
&lt;hr&gt;
&lt;p&gt;实际上，上古时代并遥远，大概在 30 年前吧，甚至更近。那个时候上网的人很少，网站架构简单地一踏糊涂。&lt;/p&gt;
&lt;p&gt;&lt;img alt="上古时代" src="/images/web_arch_the_ancient_times.png"&gt;&lt;/p&gt;
&lt;p&gt;就一个数据库加一个应用服务器，应用服务器直接开门迎客。有时候，数据库和应用服务器还运行在同一台主机上，简洁得一踏糊涂。如果你认为这种架构只能做简单的事情 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;网站架构的演进不外乎两个原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户越来越多，意味着并发要求越来越高&lt;/li&gt;
&lt;li&gt;数据越来越多，意味着存储挑战越来越大&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;上古时代&lt;/h4&gt;
&lt;hr&gt;
&lt;p&gt;实际上，上古时代并遥远，大概在 30 年前吧，甚至更近。那个时候上网的人很少，网站架构简单地一踏糊涂。&lt;/p&gt;
&lt;p&gt;&lt;img alt="上古时代" src="/images/web_arch_the_ancient_times.png"&gt;&lt;/p&gt;
&lt;p&gt;就一个数据库加一个应用服务器，应用服务器直接开门迎客。有时候，数据库和应用服务器还运行在同一台主机上，简洁得一踏糊涂。如果你认为这种架构只能做简单的事情，那就错了。这种架构也不泛一些大型的应用场景，典型的如银行的信息系统。只是，主机要用 IBM 的大型机，数据库用 Oracle，存储器要用 EMC 。这种架构还有一个特点是贵，死贵。多年之后，一场轰轰烈烈地去 IOE 运行席卷神州大地，前期就是为了解决贵的问题，当然这是后话了。&lt;/p&gt;
&lt;h4&gt;读写分离&lt;/h4&gt;
&lt;hr&gt;
&lt;p&gt;数据库在执行写操作时，需要锁定数据表，这是为了保持数据一致性。想像一下，数据库写了一半，有人读取了数据，它读出来的数据可能是不完整的。&lt;/p&gt;
&lt;p&gt;这带来的一个问题，当数据库写得比较频繁，读往往得不到执行，因为数据库老是被锁住。表现在用户层面，网速很快的情况下，一个网页显示得好久都显示不出来，这是因为数据库的读操作得不到执行。&lt;/p&gt;
&lt;p&gt;读写分离就是为了解决这个问题的，核心要点是一个 Master 数据库负责数据写入，另外有一到多个 Slave 数据库负责数据读取。Master 和 Slave 之间的数据会自动同步。&lt;/p&gt;
&lt;p&gt;&lt;img alt="读写分离" src="/images/web_arch_rw_sep.png"&gt;&lt;/p&gt;
&lt;h4&gt;负载均衡&lt;/h4&gt;
&lt;hr&gt;
&lt;p&gt;随着用户量越来越多，应用服务器开始忙不过来了。假设一个应用服务器可以运行 10 个 worker 线程，每个 worker 线程给用户提供服务的时间需要 10 毫秒，那么一个应用服务器只能满足 1000 次/秒的服务请求。超过了这个量级，就需要增加应用服务器，这个时候就引入了负载均衡服务器。&lt;/p&gt;
&lt;p&gt;负载均衡服务器负责接收用户发过来的请求，然后看哪个应用服务器比较有空闲，就把请求发送给相应的应用服务器执行。就像部门领导一样，本身自己不做事，只负责把任务分配给空闲的工程师。&lt;/p&gt;
&lt;p&gt;&lt;img alt="负载均衡" src="/images/web_arch_work_balance.png"&gt;&lt;/p&gt;
&lt;h4&gt;动静分离&lt;/h4&gt;
&lt;hr&gt;
&lt;p&gt;网站有静态内容和动态内容之分，比如我们上新浪微博网站，网站上的 Logo 就属于静态内容，它是不变的 (这里是指用户无法改变它，实际上微博的开发工程师是可以，也会改变它的)，而用户发的微博属于动态内容，它是频繁改变的。用更专业的术语讲，JavaScript，CSS，网站图片属于静态内容。&lt;/p&gt;
&lt;p&gt;为了进一步提高性能，可以把静态的内容和动态的内容分离，分别放在不同的服务器上。毕竟，静态的内容不需要读数据库，也不需要经过应用服务器的逻辑运算，可以直接把静态内容发送给用户。这样可以减少中间交互环节，从而提高效率。&lt;/p&gt;
&lt;p&gt;&lt;img alt="动静分离" src="/images/web_arch_static_dynamic_sep.png"&gt;&lt;/p&gt;
&lt;h4&gt;内容分发网络&lt;/h4&gt;
&lt;hr&gt;
&lt;p&gt;当用户进一步增长，一个负载均衡服务器搞不定了。更要命的是，北方的用户访问速度还可以，南方的用户访问起来奇慢无比。这个时候，CDN 闪亮登场了。&lt;/p&gt;
&lt;p&gt;CDN 全称是内容分发网络 (Content Delivery Network)，它的原理很简单，让一个区域的用户访问那个区域的服务器。比如北方用户从青岛服务器获取数据，华南用户从杭州服务器获取数据，西南用户从广州服务器获取数据。这种分而治之的策略特别适用于静态内容。&lt;/p&gt;
&lt;p&gt;&lt;img alt="内容分发网络" src="/images/web_arch_cdn.png"&gt;&lt;/p&gt;
&lt;p&gt;这里有一个问题，怎么样让一部分用户从 &lt;strong&gt;负载均衡服务器 1&lt;/strong&gt; 访问，另外一部分从 &lt;strong&gt;负载均衡服务器 2&lt;/strong&gt; 访问？&lt;/p&gt;
&lt;p&gt;这里就涉及到动态 &lt;strong&gt;DNS 解析&lt;/strong&gt;的技术，我们知道普通的 DNS 解析就是从一个域名获得一个或多个对应的 IP 地址信息，这个信息是不变的，即不管是北方用户还是南方用户，获取到的信息是一样的。而动态 DNS 解析，会根据用户的 IP 地址所在的地理位置以及所处的网络运营商的拓扑结构中的位置，返回最靠近的一个 IP 地址给用户。这样就实现了用户的分流，而且实现就近访问原则，从而提高效率。&lt;/p&gt;
&lt;h4&gt;数据库集群&lt;/h4&gt;
&lt;hr&gt;
&lt;p&gt;大家看到上面的架构图，是不是有点头重脚轻的感觉？没错，单纯的读写分享已经无法满足海量数据和海量并发的需求了。这个时候，就需要大容量的分布式数据库登场了。&lt;/p&gt;
&lt;p&gt;&lt;img alt="分布式数据库" src="/images/web_arch_dist_db.png"&gt;&lt;/p&gt;
&lt;p&gt;分布式数据库的优点是，可以有多个数据中心，在每个数据中心都可以支持读写，后台会自动完成数据同步工作。这个在持续不间断服务领域也是个良好的应用，因为即使一个数据中心损坏了（着火，烧掉了），也可以从另外一个数据中心恢复出数据。&lt;/p&gt;
&lt;p&gt;还有一个优点，当数据容量增大，需要扩容时，可以无缝扩容。即应用服务器不受影响。应用服务器只和数据库路由打交道，扩容可以在背后进行。&lt;/p&gt;
&lt;h4&gt;缓存&lt;/h4&gt;
&lt;hr&gt;
&lt;p&gt;从数据库里读数据还是慢，有没有办法把经常读的数据放在缓存里来提高效率呢？这就是 memcached, Redis 干的事情。这样演进后的架构变成了这样：&lt;/p&gt;
&lt;p&gt;&lt;img alt="缓存" src="/images/web_arch_cached.png"&gt;&lt;/p&gt;
&lt;h4&gt;总结&lt;/h4&gt;
&lt;hr&gt;
&lt;p&gt;看起来很简单，很自然的演进，都是 IT 技术人员数十年努力的结果，绝不简单，绝不容易。如果和研发的开会，你要是说，不是很简单吗，加个分布式数据库不就可以解决问题么？我敢保证程序员们会在内心鄙视你，如果你不是发工资的那个人，鄙视还可能溢于言表。&lt;/p&gt;</content><category term="architecture"></category></entry><entry><title>.NET in Linux Web 服务器配置</title><link href="https://blog.lonelylty.com/articles/2016/07/28/dontnet-web-server-configuration-in-linux/" rel="alternate"></link><published>2016-07-28T14:57:00+02:00</published><updated>2016-07-28T14:57:00+02:00</updated><author><name>nick</name></author><id>tag:blog.lonelylty.com,2016-07-28:/articles/2016/07/28/dontnet-web-server-configuration-in-linux/</id><summary type="html">&lt;blockquote&gt;
&lt;h4&gt;安装linux&lt;/h4&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先我们要做的就是安装linux，其发行版redhat,ubuntu,centos等等都可以，我选择了centos.&lt;/p&gt;
&lt;p&gt;1.下载 &lt;a href="https://www.centos.org/download" target="_blank"&gt;centos&lt;/a&gt;,安装过程这里不再赘述&lt;/p&gt;
&lt;p&gt;2.服务器装好系统之后，更新系统 (耗时操作,可选择执行)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;yum -y update&lt;/code&gt; 升级所有包，改变软件设置和系统设置 …&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;h4&gt;安装linux&lt;/h4&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先我们要做的就是安装linux，其发行版redhat,ubuntu,centos等等都可以，我选择了centos.&lt;/p&gt;
&lt;p&gt;1.下载 &lt;a href="https://www.centos.org/download" target="_blank"&gt;centos&lt;/a&gt;,安装过程这里不再赘述&lt;/p&gt;
&lt;p&gt;2.服务器装好系统之后，更新系统 (耗时操作,可选择执行)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;yum -y update&lt;/code&gt; 升级所有包，改变软件设置和系统设置,系统版本内核都升级&lt;/p&gt;
&lt;p&gt;&lt;code&gt;yum -y upgrade&lt;/code&gt; 升级所有包，不改变软件设置和系统设置，系统版本升级，内核不改变&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4&gt;安装mono&lt;/h4&gt;
&lt;/blockquote&gt;
&lt;p&gt;在linux上安装mono,以便跑我们写的.net应用，另外对.net core感兴趣的同学也可以去试试，就不用装mono了,不过自己写的站点在迁移时就都要用.net core重新生成一遍了,这里有篇博文可以看看&lt;a href="http://www.cnblogs.com/shanyou/p/4295163.html" target="_blank"&gt;http://www.cnblogs.com/shanyou/p/4295163.html&lt;/a&gt;，个人认为目前成熟的解决方案还是mono&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.安装Mono源码依赖库&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;yum -y install gcc gcc-c++ bison pkgconfig glib2-devel gettext make libpng-devel libjpeg-devel libtiff-devel libexif-devel giflib-devel libX11-devel freetype-devel fontconfig-devel  cairo-devel
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;可能还需要安装cmake，我在配置mono的时候遇到&lt;/p&gt;
&lt;p&gt;&lt;img alt="mono依赖" src="/images/jexus/mono_config_error.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="mono依赖" src="/images/jexus/mono_gcc.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.安装Mono需要的GDI+ 兼容API库 - Libgdiplus&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Libgdiplus是一个Mono库，用于对非Windows操作系统提供GDI+兼容的API。libgdiplus是mono中的System.Drawing依赖的一个组件，用于显示web页面基本颜色等。最新版本查看地址：&lt;a href="http://download.mono-project.com/sources/libgdiplus/" target="_blank"&gt;http://download.mono-project.com/sources/libgdiplus/&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cd /usr/local/src/

wget http://download.mono-project.com/sources/libgdiplus/libgdiplus-x.xx.tar.bz2 具体版本视情况而定

tar -jxvf libgdiplus-x.xx.tar.bz2

cd libgdiplus-x.xx

./configure --prefix=/usr

make

make install
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;img alt="monogdi插件" src="/images/jexus/mono_gdiplus.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="monogdi插件" src="/images/jexus/mono_gdi_configure.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="monogdi插件" src="/images/jexus/mono_gdi_configure_summary.png"&gt;&lt;/p&gt;
&lt;p&gt;Tips:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;tar [-cxtzjvfpPN] 文件与目录 ....
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;参数： &lt;/p&gt;
&lt;p&gt;-c ：建立一个压缩文件的参数指令(create 的意思)； &lt;/p&gt;
&lt;p&gt;-x ：解开一个压缩文件的参数指令！ &lt;/p&gt;
&lt;p&gt;-t ：查看 tarfile 里面的文件！ &lt;/p&gt;
&lt;p&gt;特别注意，在参数的下达中， c/x/t 仅能存在一个！不可同时存在！因为不可能同时压缩与解压缩。&lt;/p&gt;
&lt;p&gt;-z ：是否同时具有 gzip 的属性？亦即是否需要用 gzip 压缩？ &lt;/p&gt;
&lt;p&gt;-j ：是否同时具有 bzip2 的属性？亦即是否需要用 bzip2 压缩？ &lt;/p&gt;
&lt;p&gt;-v ：压缩的过程中显示文件！这个常用，但不建议用在背景执行过程！ &lt;/p&gt;
&lt;p&gt;-f ：使用档名，请留意，在 f 之后要立即接档名喔！不要再加参数&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.安装 mono&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最新版本查看地址：&lt;a href="http://download.mono-project.com/sources/mono/" target="_blank"&gt;http://download.mono-project.com/sources/mono/&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cd /usr/local/src/

wget http://download.mono-project.com/sources/mono/mono-x.xx.x.tar.bz2 具体版本视情况而定

tar -jxvf mono-x.xx.x.tar.bz2

cd mono-x.xx.x

./configure --prefix=/usr

make

make install
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;img alt="mono配置" src="/images/jexus/mono_dowload.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="mono配置" src="/images/jexus/mono_configure.png"&gt;&lt;/p&gt;
&lt;p&gt;经过漫长的编译过程，大概需要半小时左右,输入&lt;code&gt;mono -V&lt;/code&gt; 有mono版本信息,则安装成功&lt;/p&gt;
&lt;p&gt;&lt;img alt="mono配置" src="/images/jexus/mono_configure_summary.png"&gt;&lt;/p&gt;
&lt;p&gt;Tips:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;源码的安装一般由3个步骤组成：配置(configure)、编译(make)、安装(make install)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;--prefix选项是配置安装的路径，如果不配置该选项，安装后可执行文件默认放在/usr /local/bin，库文件默认放在/usr/local/lib，配置文件默认放在/usr/local/etc，其它的资源文件放在/usr /local/share，比较凌乱&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;h4&gt;安装jexus&lt;/h4&gt;
&lt;/blockquote&gt;
&lt;p&gt;选择国产的jexus作为web服务器，选这个应该是先入为主的感觉...还有就是有个 &lt;a href="https://www.linuxdot.net/" target="_blank"&gt;linuxdotnet社区&lt;/a&gt;，jexus配置教程和常见问题，都能在这里找到答案。把解压所得到的文件及文件夹全部复制或移动到 /usr/jexus 这个文件夹中即可&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cd /tmp
wget http://www.linuxdot.net/down/jexus-x.x.x.tar.gz
tar -zxvf jexus-x.x.x.tar.gz
sudo mv jexus /usr/
cd /usr/jexus
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;img alt="jexus目录" src="/images/jexus/jexus_folder.png"&gt;&lt;/p&gt;
&lt;p&gt;Tips: &lt;/p&gt;
&lt;p&gt;注意安装的centos版本，centos从7.x开始默认用的是firewalld，这个是基于iptables的，虽然有iptables的核心，但是iptables的服务是没安装的，低于7的还是可以使用iptables,将80端口打开&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;firewall-cmd --zone=public --query-port=80/tcp 查看
firewall-cmd --zone=public --add-port=80/tcp --permanent   添加 （--permanent永久生效，没有此参数重启后失效）
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;CentOS 6.x装好mono和Jexus后，在 /ect/rc.local 后面添加 /usr/jexus/jws start 就可以让jexus跟随系统一起启动,然而在CentOS 7.x上用上面的方法却行不通&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;vi /lib/systemd/system/jexus.service
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;写入如下脚本&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Description=jexus                   描述服务
After=network.target                描述服务类别
[Service]                           服务运行参数的设置
Type=forking                        后台运行的形式
ExecStart=/usr/jexus/jws start      服务的具体运行命令
ExecReload=/usr/jexus/jws restart   重启命令
ExecStop=/usr/jexus/jws stop        停止命令
PrivateTmp=true                     表示给服务分配独立的临时空间
[Install]                           服务安装的相关设置，可设置为多用户
WantedBy=multi-user.target
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;img alt="jexus自启动" src="/images/jexus/jexus_self_start.png"&gt;&lt;/p&gt;
&lt;p&gt;修改时注意服务的路径，你也可以从/lib/systemd/system 文件夹下复制一个service结尾的文件，改名后修改里面的内容。修改后 设置权限 加入到服务中去&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;chmod 754 jexus.service 
systemctl enable jexus.service
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;最后reboot看看有没有生效&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4&gt;安装nginx&lt;/h4&gt;
&lt;/blockquote&gt;
&lt;p&gt;选择nginx作为反向代理服务器，个人感觉小型站点使用这个，有点杀鸡用牛刀的赶脚，这里也不班门弄斧了，这里有个 &lt;a href="http://www.runoob.com/linux/nginx-install-setup.html" target="_blank"&gt;教程地址&lt;/a&gt; ，感觉写的还不错&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4&gt;结语&lt;/h4&gt;
&lt;/blockquote&gt;
&lt;p&gt;最后根据不同的业务，选择合适的数据库,whatever you want! 在这里给出linux上安装mysql&lt;a href="http://www.runoob.com/linux/mysql-install-setup.html" target="_blank"&gt;教程地址&lt;/a&gt;：如果是个人站点，完全可以装在同一台服务器，如果用户访问量较大，建议还是单独弄一台服务器跑数据库&lt;/p&gt;</content><category term="linux"></category></entry><entry><title>正则速查</title><link href="https://blog.lonelylty.com/articles/2016/06/12/regex/" rel="alternate"></link><published>2016-06-12T09:57:00+02:00</published><updated>2016-06-12T09:57:00+02:00</updated><author><name>nick</name></author><id>tag:blog.lonelylty.com,2016-06-12:/articles/2016/06/12/regex/</id><summary type="html">&lt;h5&gt;常用元字符&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;符号&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.&lt;/td&gt;
&lt;td&gt;匹配除换行符以外的任意字符。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\w&lt;/td&gt;
&lt;td&gt;匹配字母或数字或下划线或汉字。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\s&lt;/td&gt;
&lt;td&gt;匹配任意的空白符。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\d&lt;/td&gt;
&lt;td&gt;匹配数字。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\b&lt;/td&gt;
&lt;td&gt;匹配单词的开始或结束。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[ck]&lt;/td&gt;
&lt;td&gt;匹配包含括号内元素的字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;^&lt;/td&gt;
&lt;td&gt;匹配行的开始。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$&lt;/td&gt;
&lt;td&gt;匹配行的结束。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\&lt;/td&gt;
&lt;td&gt;对下一个字符转义。比如$是个特殊    的字符 …&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;</summary><content type="html">&lt;h5&gt;常用元字符&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;符号&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.&lt;/td&gt;
&lt;td&gt;匹配除换行符以外的任意字符。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\w&lt;/td&gt;
&lt;td&gt;匹配字母或数字或下划线或汉字。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\s&lt;/td&gt;
&lt;td&gt;匹配任意的空白符。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\d&lt;/td&gt;
&lt;td&gt;匹配数字。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\b&lt;/td&gt;
&lt;td&gt;匹配单词的开始或结束。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[ck]&lt;/td&gt;
&lt;td&gt;匹配包含括号内元素的字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;^&lt;/td&gt;
&lt;td&gt;匹配行的开始。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$&lt;/td&gt;
&lt;td&gt;匹配行的结束。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\&lt;/td&gt;
&lt;td&gt;对下一个字符转义。比如$是个特殊    的字符。要匹配$的话就得用\$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;反义元字符&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;符号&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;\W&lt;/td&gt;
&lt;td&gt;匹配任意不是字母，数字，下划线，汉字的字符。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\S&lt;/td&gt;
&lt;td&gt;匹配任意不是空白符的字符。等价于 [^ \f\n\r\t\v]。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\D&lt;/td&gt;
&lt;td&gt;匹配任意非数字的字符。等价于 [^0-9]。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\B&lt;/td&gt;
&lt;td&gt;匹配不是单词开头或结束的位置。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[^CK]&lt;/td&gt;
&lt;td&gt;匹配除了CK以外的任意字符。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;特殊元字符&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;符号&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;\f&lt;/td&gt;
&lt;td&gt;匹配一个换页符。等价于 \x0c 和 \cL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\n&lt;/td&gt;
&lt;td&gt;匹配一个换行符。等价于 \x0a 和 \cJ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\r&lt;/td&gt;
&lt;td&gt;匹配一个回车符。等价于 \x0d 和 \cM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\t&lt;/td&gt;
&lt;td&gt;匹配一个制表符。等价于 \x09 和 \cI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\v&lt;/td&gt;
&lt;td&gt;匹配一个垂直制表符。等价于 \x0b 和 \cK&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;限定符&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;符号&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;*&lt;/td&gt;
&lt;td&gt;匹配前面的子表达式零次或多次。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;匹配前面的子表达式一次或多次。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;匹配前面的子表达式零次或一次。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td n&gt;&lt;/td&gt;
&lt;td&gt;n 是一个非负整数。匹配确定的 n 次。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td n_="n,"&gt;&lt;/td&gt;
&lt;td&gt;n 是一个非负整数。至少匹配n 次。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td n_m="n,m"&gt;&lt;/td&gt;
&lt;td&gt;m 和 n 均为非负整数，其中n &amp;lt;= m。最少匹配 n 次且最多匹配 m 次。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;懒惰限定符&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;符号&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;*?&lt;/td&gt;
&lt;td&gt;重复任意次，但尽可能少重复。&lt;br&gt;  如 "acbacb" 正则 "a.*?b" 只会取到第一个"acb" 原本可以全部取到但加了限定符后，&lt;br&gt;只会匹配尽可能少的字符 ，而"acbacb"最少字符的结果就是"acb" 。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+?&lt;/td&gt;
&lt;td&gt;重复1次或更多次，但尽可能少重复。与上面一样，只是至少要重复1次。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;??&lt;/td&gt;
&lt;td&gt;重复0次或1次，但尽可能少重复。如 "aaacb" 正则 "a.??b" 只会取到最后的三个字符"acb"。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td n_m="n,m"&gt;&lt;/td&gt;
&lt;td 0_m="0,m"&gt;重复n到m次，但尽可能少重复。如 "aaaaaaaa"  正则 "a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td n_="n,"&gt;&lt;/td&gt;
&lt;td 1_="1,"&gt;重复n次以上，但尽可能少重复。如 "aaaaaaa"  正则 "a&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;捕获分组&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;符号&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;(exp)&lt;/td&gt;
&lt;td&gt;匹配exp,并捕获文本到自动命名的组里。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?&lt;name&gt;exp)&lt;/td&gt;
&lt;td&gt;匹配exp,并捕获文本到名称为name的组里。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?:exp)&lt;/td&gt;
&lt;td&gt;匹配exp,不捕获匹配的文本，也不给此分组分配组号以下为零宽断言。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?=exp)&lt;/td&gt;
&lt;td&gt;匹配exp前面的位置。&lt;br&gt;如 "How are you doing" 正则"(?&lt;txt&gt;.+(?=ing))" 这里取ing前所有的字符，&lt;br&gt;并定义了一个捕获分组名字为 "txt" 而"txt"这个组里的值为"How are you do";&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?&amp;lt;=exp)&lt;/td&gt;
&lt;td&gt;匹配exp后面的位置。&lt;br&gt;如 "How are you doing" 正则"(?&lt;txt&gt;(?&amp;lt;=How).+)" 这里取"How"之后所有的字符，&lt;br&gt;并定义了一个捕获分组名字为 "txt" 而"txt"这个组里的值为" are you doing";&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?!exp)&lt;/td&gt;
&lt;td 3&gt;匹配后面跟的不是exp的位置。如 "123abc" 正则 "\d&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?&amp;lt;!exp)&lt;/td&gt;
&lt;td&gt;匹配前面不是exp的位置。&lt;br&gt;如 "abc123 " 正则 "(?&amp;lt;![0-9])123" 匹配"123"前面是非数字的结果也可写成"(?!&amp;lt;\d)123"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;牛刀小试一下下，常用正则Query封装&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;_reg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="cm"&gt;/* &amp;#39;pwd&amp;#39;:/^[\@A-Za-z0-9\!\#\$\%\^\&amp;amp;\*\.\~]{6,16}$/,//密码 */&lt;/span&gt;
    &lt;span class="c1"&gt;//验证数字&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_reg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;num&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^\d+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//数字&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;znum&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^[1-9](\d+)?$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//  大于0的数字&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;float&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^[-]{0,1}(\d+)[\.]+(\d+)$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//浮点数&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;money&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^\d{1,12}(?:\.\d{1,3})?$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// money&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;idCard&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^\d{15}$|^\d{18}$|^\d{17}[xX]$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//身份证&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;idCardStrict&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;/^(\d{6})([1-2])(\d{3})((?:0[1-9])|(?:1[0-2]))((?:0[0-9])|(?:[1-2][0-9])|(?:3[0-1]))(\d{3})(\d{1})$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;qq&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^[1-9]\d{4,15}$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//QQ&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;pwd&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^[\@A-Za-z0-9]{6,16}$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//密码&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;areacode&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^(0[1,2]{1}\d{1})$|^(0[3-9]{1}\d{2})$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//区号&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;tel&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^\d{7,8}$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 固话格式&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;mobile&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^((\+86)|(\(\+86\)))?-?(13|14|15|18|17)[0-9]{9}$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//验证手机号码&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;telephone&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^(((\+)?86)|(\(\+86\)))?-?((((0)?[1,2]{1}\d{1})?-?\d{8})|((0[3-9]{1}\d{2})?-?\d{7,12}))-?(\d{1,8})?$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//验证固定电话&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;phone&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^((\+86)|(\(\+86\)))?-?(13|14|15|18|17)[0-9]{9}$|^((\+86)|(\(\+86\)))?-?(((0[1,2]{1}\d{1})?-?\d{8})|((0[3-9]{1}\d{2})?-?\d{7,8}))$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//手机号码和固定电话&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;zipcode&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^\d{6}$/&lt;/span&gt; &lt;span class="c1"&gt;//验证邮编&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="c1"&gt;//验证字符串&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_reg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;email&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^\w{1,16}([-+.&amp;#39;]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//邮箱&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;chinese&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^[\u4E00-\u9FA5]+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//仅汉字&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;char&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^[A-Za-z]+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//仅仅是字母&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;charn&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^[A-Za-z0-9]+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//数字加字母&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;nospecial&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^[\u4E00-\u9FA5A-Za-z0-9]+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 不包含特殊字符&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;url&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^((http|https|ftp):\/\/)?(\w(\:\w)?@)?([0-9a-z_-]+\.)*?([a-z0-9-]+\.[a-z]{2,6}(\.[a-z]{2})?(\:[0-9]{2,6})?)((\/[^?#&amp;lt;&amp;gt;\/\\*&amp;quot;:]*)+(\?[^#]*)?(#.*)?)?$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;loginName&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^(13|14|15|18|17)[0-9]{9}$|^\w+([-+.&amp;#39;]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 用户名&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;userName&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^[\u4e00-\u9fa5]{2`,4}$|[a-zA-Z]{4,20}$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//真实姓名&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;nickName&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^([a-zA-Z\u4e00-\u9fa5]{1}[a-zA-Z0-9_\u4e00-\u9fa5]{3,19})$/&lt;/span&gt; &lt;span class="c1"&gt;//昵称&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;_reg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jQuery&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</content><category term="regex"></category></entry><entry><title>Markdown 11种基本语法</title><link href="https://blog.lonelylty.com/articles/2016/05/31/markdown/" rel="alternate"></link><published>2016-05-31T16:57:00+02:00</published><updated>2016-05-31T16:57:00+02:00</updated><author><name>nick</name></author><id>tag:blog.lonelylty.com,2016-05-31:/articles/2016/05/31/markdown/</id><summary type="html">&lt;h5&gt;1. 标题设置（让字体变大，和word的标题意思一样）&lt;/h5&gt;
&lt;p&gt;在Markdown当中设置标题，有两种方式：
第一种：通过在文字下方添加“=”和“-”，他们分别表示一级标题和二级标题。
第二种：在文字开头加上 “#”，通过“#”数量表示几级标题。（一共只有1~6级标题，1级标题字体最大）&lt;/p&gt;
&lt;h5&gt;2. 块注释（blockquote …&lt;/h5&gt;</summary><content type="html">&lt;h5&gt;1. 标题设置（让字体变大，和word的标题意思一样）&lt;/h5&gt;
&lt;p&gt;在Markdown当中设置标题，有两种方式：
第一种：通过在文字下方添加“=”和“-”，他们分别表示一级标题和二级标题。
第二种：在文字开头加上 “#”，通过“#”数量表示几级标题。（一共只有1~6级标题，1级标题字体最大）&lt;/p&gt;
&lt;h5&gt;2. 块注释（blockquote）&lt;/h5&gt;
&lt;p&gt;通过在文字开头添加“&amp;gt;”表示块注释。（当&amp;gt;和文字之间添加五个blank时，块注释的文字会有变化。）&lt;/p&gt;
&lt;h5&gt;3. 斜体&lt;/h5&gt;
&lt;p&gt;将需要设置为斜体的文字两端使用1个“*”或者“_”夹起来&lt;/p&gt;
&lt;h5&gt;4. 粗体&lt;/h5&gt;
&lt;p&gt;将需要设置为斜体的文字两端使用2个“*”或者“_”夹起来&lt;/p&gt;
&lt;h5&gt;5. 无序列表&lt;/h5&gt;
&lt;p&gt;在文字开头添加(&lt;em&gt;, +, and -)实现无序列表。但是要注意在(&lt;/em&gt;, +, and -)和文字之间需要添加空格。（建议：一个文档中只是用一种无序列表的表示方式）&lt;/p&gt;
&lt;h5&gt;6. 有序列表&lt;/h5&gt;
&lt;p&gt;使用数字后面跟上句号。（还要有空格）&lt;/p&gt;
&lt;h5&gt;7. 链接（Links）&lt;/h5&gt;
&lt;p&gt;Markdown中有两种方式，实现链接，分别为内联方式和引用方式。&lt;/p&gt;
&lt;p&gt;内联方式：This is an &lt;a href="http://example.com/"&gt;example link&lt;/a&gt;.
引用方式：
I get 10 times more traffic from &lt;a href="http://google.com/" title="Google"&gt;Google&lt;/a&gt; than from &lt;a href="http://search.yahoo.com/" title="Yahoo Search"&gt;Yahoo&lt;/a&gt; or &lt;a href="http://search.msn.com/" title="MSN Search"&gt;MSN&lt;/a&gt;.  &lt;/p&gt;
&lt;h5&gt;8. 图片（Images）&lt;/h5&gt;
&lt;p&gt;图片的处理方式和链接的处理方式，非常的类似。
内联方式：&lt;img alt="alt text" src="/path/to/img.jpg" title="Title"&gt;
引用方式：&lt;img alt="alt text" src="/path/to/img.jpg" title="Title"&gt; &lt;/p&gt;
&lt;h5&gt;9. 代码（HTML中所谓的Code）&lt;/h5&gt;
&lt;p&gt;实现方式有两种：
第一种：简单文字出现一个代码框。使用&lt;code&gt;&amp;lt;blockquote&amp;gt;&lt;/code&gt;。（&lt;code&gt;不是单引号而是左上角的ESC下面~中的&lt;/code&gt;）
第二种：大片文字需要实现代码框。使用Tab和四个空格。&lt;/p&gt;
&lt;h5&gt;10. 脚注（footnote）&lt;/h5&gt;
&lt;p&gt;实现方式如下：
hello[^hello]&lt;/p&gt;
&lt;h5&gt;11. 下划线&lt;/h5&gt;
&lt;p&gt;在空白行下方添加三条“-”横线。（前面讲过在文字下方添加“-”，实现的2级标题）&lt;/p&gt;
&lt;p&gt;&lt;a href="https://stackedit.io/"&gt;推荐一款在线的Markdown编辑器&lt;/a&gt; &lt;/p&gt;</content><category term="markdown"></category></entry></feed>