醍醐灌顶https://blog.lonelylty.com/2017-01-01T09:57:00+01:00在2016年学JavaScript是一种什么样的体验2017-01-01T09:57:00+01:002017-01-01T09:57:00+01:00nicktag:blog.lonelylty.com,2017-01-01:/articles/2017/01/01/how-it-feels-to-learn-javascript-in-2016/<p><strong>嘿,我最近接到一个 Web 项目,不过老实说,我这两年没怎么接触 Web 编程,听说 Web 技术已经发生了一些变化。听说你是这里对新技术最了解的 Web 开发工程师?</strong></p>
<p><em>准确地说,我是一名「前端工程师」。不过你算是找对人了。我对今年的技术别提多熟了,前端可视化 …</em></p><p><strong>嘿,我最近接到一个 Web 项目,不过老实说,我这两年没怎么接触 Web 编程,听说 Web 技术已经发生了一些变化。听说你是这里对新技术最了解的 Web 开发工程师?</strong></p>
<p><em>准确地说,我是一名「前端工程师」。不过你算是找对人了。我对今年的技术别提多熟了,前端可视化、音乐播放器、能踢足球的无人机,你尽管问吧。我刚去 JS 大会和 React 大会逛了一圈,没有什么新技术是我不知道的。</em></p>
<p><strong>厉害。是这样的,我要开发一个网页,用来展示用户的最新动态。我想我应该通过后端接口获取数据,然后用一个 table 来展示数据,用户可以对数据进行排序。如果服务器上的数据变化了,我还需要更新这个 table。我的思路是用 jQuery 来做。</strong></p>
<p><em>可别用 jQuery!现在哪还有人用 jQuery。现在是 2016 年了,你绝对应该用 React。</em></p>
<p><strong>哦,好吧,React 是什么?</strong></p>
<p><em>React 是一个非常厉害的库,Facebook 的牛人写的。它能让页面更可控,性能极高,而且使用起来很简单。</em></p>
<p><strong>听起来确实不错。我能用 React 展示服务器传来的数据吗?</strong></p>
<p><em>当然可以,你只需要添加两个依赖,一个是 React,一个是 React DOM</em></p>
<p><strong>额,等下,为什么是两个库?</strong></p>
<p><em>React 是我说的库,React DOM 是用来操作 DOM 的。因为这些 DOM 是用 JSX 写的,所以需要一个专门的库来操作。</em></p>
<p><strong>JSX?JSX 是什么?</strong></p>
<p><em>JSX 是对 JS 的扩展,它看起来跟 XML 差不多,可以用来写 HTML,你可以认为 JSX 是一种更优雅的 HTML 写法。</em></p>
<p><strong>为什么不用 HTML 了……?</strong></p>
<p><em>现在可是 2016 年啊,没有直接写 HTML 的。</em></p>
<p><strong>对哦。好吧,加了这两个依赖,是不是就可以开始用 React 了?</strong></p>
<p><em>不行哦。你需要添加 Babel,然后才能用 React。</em></p>
<p><strong>Babel 是另一个库?</strong></p>
<p><em>嗯,Babel 是一个转译工具,Babel 能把你写的 JS 转译成任意版本的 JS。你不一定非要用 Babel,但是如果你不用的话,你就只能写 ES5 的语法了。你知道的,现在是 2016 年,你怎么能不使用 ES2016+ 的语法呢?ES2016+ 多么酷啊。</em></p>
<p><strong>ES5 是啥?ES2016+ 又是啥?我有点晕。</strong></p>
<p><em>ES5 就是 ECMAScript 5。大部分人都会使用 ES5,因为大部分浏览器都支持 ES5。</em></p>
<p><strong>ECMAScript 是啥……</strong></p>
<p><em>你晓得的,JS是1995年诞生的,而JS的标准是1999制定出来的。那时候 JavaScript 还叫做 Livescript,只能运行在网景的浏览器里。那时真是混乱的年代,现在好了,我们有了 JS 的 7 个版本的规范。</em></p>
<p><strong>7 个版本?那 ES5 和 ES2016+ 是?</strong></p>
<p><em>分别是第 5 个版本和第 7 个版本。</em></p>
<p><strong>诶,那第六个版本呢?</strong></p>
<p><em>你说的是 ES6。每个版本都是上一个版本的超集,所以你直接使用最新的 ES2016+ 就好了。</em></p>
<p><strong>对哦。为什么不用 ES6 呢?</strong></p>
<p><em>好吧,你可以用 ES6,但是你就用不到 async 和 await 这么酷的语法了。用 ES2016+ 比较好。用 ES6 的话你就只能用 generator 来控制异步任务流了。</em></p>
<p><strong>不知道你在说什么……你说了太多我听不懂的名词了。我只是想从服务器取点数据,我以前用 jQuery 挺好的,从 CDN 引入 jQuery,我就能用 AJAX 获取数据了,现在不能这样做吗?</strong></p>
<p><em>大哥,都 2016 年了,没人用 jQuery 好吗。所有人都知道用 jQuery 只会造出「意大利面条」一样的代码(不可维护)</em></p>
<p><strong>好吧,所以我现在要加载三个库才能获取并展示数据。</strong></p>
<p><em>对的,其实你可以用「模块管理器」把这三个库「打包」成一个文件。</em></p>
<p><strong>哦,什么是模块管理器……</strong></p>
<p><em>不同平台的模块管理器不同啦。前端的模块管理器一般指管理 AMD 或者 CommonJS 模块的东西。</em></p>
<p><strong>好……吧,什么是 AMD 和 CommonJS?</strong></p>
<p><em>是两个定义。我们有很多方式来描述 JS 中多个库或类的交互方式,比如 exports 和 requires。你可以按照 AMD 或者 CommonJS 的 API 来书写 JS,然后用 Browserify 将它们打包。</em></p>
<p><strong>听起来很有道理。不过,什么是 Browserify?</strong></p>
<p><em>是一个工具,用来将 CommonJS 形式的 JS 文件打包起来,放到浏览器里运行。用 npm 仓库的人发明了 CommonJS。</em></p>
<p><strong>npm 仓库是什么……</strong></p>
<p><em>是一个公开的仓库,用于放置可依赖的模块。</em></p>
<p><strong>就像一个 CDN 么?</strong></p>
<p><em>不太一样。它更像是一个数据库,每个人都能在上面发布代码,也能下载上面的代码。你可以在开发的时候将这些代码下载到本地来使用,必要的时候也能上传到 CDN。</em></p>
<p><strong>听起来像是 Bower!</strong></p>
<p><em>是的,不过现在是 2016 年了,没有人用 Bower 了……</em></p>
<p><strong>好吧,我知道了,所以我应该用 npm 来安装依赖。</strong></p>
<p><em>对的。我举个例子吧,如果你要使用 React,你直接用 npm 安装 React,然后在代码里导入 React 就可以了。大部分 JS 库都能这么安装。</em></p>
<p><strong>嗯,Angular 也可以。</strong></p>
<p><em>Angular 是 2015 年的事情了。不过今年 Angular 还没死,还有 VueJS 和 RxJS 等等,你想学一学么?</em></p>
<p><strong>还是用 React 吧。我刚才已经学了够多东西了。所以我用 npm 安装 React 然后用 Browerify 来打包就好了?</strong></p>
<p><em>是的。</em></p>
<p><strong>这么做看起来有点过于复杂啊。</strong></p>
<p><em>确实。这就是为什么你应该使用 Grunt、Gulp 或者 Broccoli 这样的任务管理工具,它们能自动运行 Browserify。不对,你现在可以用 Mimosa。</em></p>
<p><strong>你在说什么……</strong></p>
<p><em>任务管理工具。不过我们现在已经不用了。去年我们还在用,后来改成了 Makefiles,但是现在我们用的都是 Webpack。</em></p>
<p><strong>我以为只有 C/C++ 项目才会用 Makefiles。</strong></p>
<p><em>是的,不过显然我们做 Web 开发的,喜欢先把事情搞复杂,然后回归到最朴素的状态。每年我们都是这么搞的。你就看着吧,过不了两年,我们就可以在网页上写汇编了。</em></p>
<p><strong>唉,你刚才说的 Webpack 是什么?</strong></p>
<p><em>另一种模块管理工具,同时也是一个任务管理工具。你可以认为它是 Browserify 的加强版。</em></p>
<p><strong>哦,好吧,为什么 Webpack 是加强版?</strong></p>
<p><em>额,可能并没有加强吧。Webpack 告诉你应该如何管理你的依赖,Webpack 允许你使用不同的模块管理器,不只是 CommonJS,甚至支持 ES6 模块。</em></p>
<p><strong>这都是哪跟哪啊,我都被绕晕了。</strong></p>
<p><em>大家都被绕晕了,不过等 SystemJS 出来了就好了。</em></p>
<p><strong>天呐,又一个 JS 库,这是什么鬼?</strong></p>
<p><em>呵呵,不像 Browserify 和 Webpack 1.x,SystemJS 是一个动态的模块加载器。</em></p>
<p><strong>等下,刚才不是说应该把所有依赖打包成一个文件吗?</strong></p>
<p><em>话是这么说,但是等 HTTP/2 普及之后,不打包反而更好。</em></p>
<p><strong>那为什么我们不直接在页面里添加 React 的三个依赖文件呢?</strong></p>
<p><em>不行。你可以从 CDN 加载这些文件,但是你还是要在本地用 Babel 转译。</em></p>
<p><strong>唉,这么鹾?</strong></p>
<p><em>是的,你不能在生产环境上运行 babel,你应该在发布到生产环境之前,运行一系列的任务,包括压缩、混淆、内联化CSS、延迟加载script……</em></p>
<p><strong>我懂了我懂了。既然我不能直接用 CDN,那么我应该怎么做?</strong></p>
<p><em>我会考虑用 Webpack + SystemJS + Babel 来转译 Typescript。</em></p>
<p><strong>Typescript?我们不是在说 JavaScript 吗?!</strong></p>
<p><em>Typescript 也是 JavaScript 呀,它比 JS 更好用,是 JS 的超集,它是基于 ES6 的,就是我们刚才谈论的 ES6,你还记得吧。</em></p>
<p><strong>ES2016+ 已经是 ES6 的超集了,怎么又冒出来一个 Typescript?</strong></p>
<p><em>是这样的,Typescript 能让我们写出「强类型」的 JS,从而减少运行时的错误。2016年,我们应该让 JS 支持强类型了。</em></p>
<p><strong>显然 Typescript 可以做到。</strong></p>
<p><em>Flow 也可以做到,区别是 Typescript 需要编译,而 Flow 只是检查语法。</em></p>
<p><strong>唉,Flow 是?</strong></p>
<p><em>是一个静态类型检查器,就是 Facebook 的人写的。使用 OCaml 写的,函数式编程很叼的。</em></p>
<p><strong>OCaml?函数式编程?</strong></p>
<p><em>如今大牛都用这些东西,都2016年了,你懂的,函数式编程、高阶函数、柯里化、纯函数这些概念。</em></p>
<p><strong>不知道你在说什么。</strong></p>
<p><em>一开始大家都不知道。这么说吧,你只需要知道函数式编程比面向对象编程厉害,2016 年我们就指着函数式编程了。</em></p>
<p><strong>等下,我大学里学过面向对象编程,当时我觉得它还不错。</strong></p>
<p><em>Java 在被 Oracle 买下来之前也挺不错啊。我的意思是,面向对象以前是不错,现在依然有人用它,但是现在所有人都发觉状态变换是很难维护的,所以大家都开始用「不可变对象」和函数式编程了。Haskell 的人已经用这套东西用了很久了,不过幸运的是 Web 开发领域里有 Ramda 这样的库,让我们用 JS 就可以进行函数式编程了。</em></p>
<p><strong>你刚刚是不是又抛出了几个名词?Ramnda 又是什么?</strong></p>
<p><em>不是 Ramnda,是 Ramda,跟 Lambda 表达式有点像。是 David Chambers 写的库。</em></p>
<p><strong>谁?</strong></p>
<p><em>David Chambers,大神一个。blablabla</em></p>
<p><strong>我不得不打断你一下了。这些东西看起来都不错,但是我觉得它们都太复杂,而且没必要。我只是想获取数据然后展示,我很确定这种情况下我不需要掌握这些知识。</strong></p>
<p><strong>回到 React 吧,用 React 我怎么从服务器获取数据?</strong></p>
<p><em>额,React 没有提供这个功能,你只能用 React 展示数据。</em></p>
<p><strong>服了啊。那我怎么获取数据?</strong></p>
<p><em>你用 Fetch API 就可以了。</em></p>
<p><strong>啥玩意?这个 API 的名字很烂啊。</strong></p>
<p><em>我也觉得是啊。Fetch API 是浏览器提供的异步请求接口。</em></p>
<p><strong>哦,那不就是 AJAX。</strong></p>
<p><em>AJAX 只是使用 XMLHttpRequest 对象,但是 Fetch API 可以让你用 Promise 风格来发起异步请求,帮你摆脱「回调地狱」。</em></p>
<p><strong>回调地狱?</strong></p>
<p><em>是的,每次你发起一个异步请求,就得等待它响应。这时你就得在函数里使用一个函数,这种嵌套调用就是回调地狱。</em></p>
<p><strong>好吧。Promise 解决了这个问题么?</strong></p>
<p><em>是的。用 Promise 来管理回调,你就可以写出更易读的代码,更容易测试的代码。甚至可以同时发起多个请求,然后等待它们全部返回。</em></p>
<p><strong>Fetch 也能做到吗?</strong></p>
<p><em>是的。但前提是你的用户使用了新版的浏览器,不然的话你就需要加一个 Fetch 的 「polyfill」,或者使用 Request、Bluebird 或者 Axios 这些库。</em></p>
<p><strong>天呐我到底需要多少个库?</strong></p>
<p><em>这是 JS,同一件事情有上千个库在做。我们了解库,而且我们有最好的库,我们有海量的库,要什么有什么。</em></p>
<p><strong>你刚才说的几个库都是干什么的?</strong></p>
<p><em>这几个库操作 XMLHttpRequest 然后返回 Promise 对象。</em></p>
<p><strong>好像 jQuery 的 ajax 方法做的是同样的事吧……</strong></p>
<p><em>从 2016 年起我们就不用 jQuery 了。用 Fetch,大不了加个 Polyfill,要不然用 Bluebird、Request 或者 Axios 都行。然后用 await 和 async 管理 Promise,这样才能控制好异步任务。</em></p>
<p><strong>这是你第三次说 await 了,那是什么东西?</strong></p>
<p><em>await 能让你拦住一个异步调用,让你更好地控制异步返回的数据,大大增强了代码的可读性。await 非常好用,你只需要在 Babel 里添加 stage–3 配置,或者添加 syntax-async-functions 和 transform-async-to-generator 插件就可以了。</em></p>
<p><strong>听起来像是疯了。</strong></p>
<p><em>没疯。为了使用 await,把 Typescript 编译之后再用 Babel 转译一道的人才是疯了。</em></p>
<p><strong>啥玩意?Typescript 不支持 await?</strong></p>
<p><em>下个版本就支持了。</em></p>
<p><strong>我已经无话可说了。</strong></p>
<p><em>你看其实很简单。用 Typescript 写代码,用 Fetch 发起异步请求,所有代码编译成 ES6,然后用上 Babel 的 stage–3 配置项,把 ES6 转译成 ES5。所有代码用 SystemJS 加载。如果你用不了 Fetch,就加个 polyfill,或者用 Bluebird、Request 或者 Axios,这样你就可以用 await 来处理 Promise 了。</em></p>
<p><strong>看来我们俩对于「简单」的理解是不同的。好吧,有了这些,我终于可以获取数据然后用 React 展示数据了,对吧?</strong></p>
<p><em>你的网页需要处理状态变更吗?</em></p>
<p><strong>唔,不用吧。我只是想展示数据。</strong></p>
<p><em>那就好,不然我就得跟你解释 Flux,以及 Flux 的一些实现,比如 Flummox、Alt、Fluxible。不过说真的你应该用 Redux。</em></p>
<p><strong>你说的这些我就当耳旁风了。再说一次,我只想展示数据。</strong></p>
<p><em>这样啊,如果你只是想展示数据,其实你不需要 React。你只需要一个模板引擎。</em></p>
<p><strong>你逗我呢?</strong></p>
<p><em>我只是告诉你你可以用什么技术。</em></p>
<p><strong>别说了,真的。</strong></p>
<p><em>我想说,即使只是用一个模板引擎,我还是会用 Typescript + SystemJS + Babel 的。</em></p>
<p><strong>我只是想在页面上展示数据,你就告诉我用哪个模板引擎就好了。</strong></p>
<p><em>有很多,你用过哪一个?</em></p>
<p><strong>额,太久没用了,不记得了。</strong></p>
<p><em>jTemplates、jQote 还是 PURE?</em></p>
<p><strong>额,不记得,还有别的么?</strong></p>
<p><em>Transparency? JSRender? MarkupJS? KnockoutJS? 这一个支持双向绑定。</em></p>
<p><strong>还有吗?</strong></p>
<p><em>PlatesJS? jQuery-tmpl? Handlebars? 还有些人在用。</em></p>
<p><strong>有点像。有哪些跟最后一个比较像的?</strong></p>
<p><em>Mustache, underscore? 我记得连 Lodash 都有一个模板引擎,不过这是 2014 年的事情了。</em></p>
<p><strong>额,也许是再新一点的库?</strong></p>
<p><em>Jade? DustJS?</em></p>
<p><strong>没用过</strong></p>
<p><em>DotJS? EJS?</em></p>
<p><strong>没用过。</strong></p>
<p><em>Nunjucks? ECT?</em></p>
<p><strong>没用过。记不起来了,要是你的话,你用哪个?</strong></p>
<p><em>我应该会用 ES6 原生的模板字符串</em></p>
<p><strong>我猜猜,只有 ES6 支持。</strong></p>
<p><em>对的。</em></p>
<p><strong>需要用 Babel</strong></p>
<p><em>对的。</em></p>
<p><strong>需要用 npm 安装</strong></p>
<p><em>对的。</em></p>
<p><strong>需要用 Browserify 或者 Webpack,或者 SystemJS</strong></p>
<p><em>对的。</em></p>
<p><strong>如果没用 Webpack 的话,我还需要一个任务管理工具。</strong></p>
<p><em>对的。</em></p>
<p><strong>但是由于我要用函数式编程和强类型语言,所以我首先要用上 Typescript 或者 Flow。</strong></p>
<p><em>对的。</em></p>
<p><strong>如果我要用 await,那我就必须用 Babel 转译。</strong></p>
<p><em>对的。</em></p>
<p><strong>然后我就能用上 Fetch、Promise 和各种炫酷的东西。</strong></p>
<p><em>嗯,别忘了加上 Fetch 的 Polyfill,因为 Safari 不支持 Fetch。</em></p>
<p><strong>你猜怎么着,我们就聊到这吧。我不做了,我不做 Web 了,我也不想再碰 JS 了。</strong></p>
<p><em>没事,过不了几年,我们都会用 Elm 或者 WebAssembly 了。</em></p>
<p><strong>我要回后端去了,我受不这些变动、版本更新、编译和转译了,JS 社区如果觉得有人能跟上它的脚步,那这个社区就是疯了。</strong></p>
<p><em>我理解你。我建议你去 Python 社区。</em></p>
<p><strong>为什么?</strong></p>
<p><em>听说过 Python 3 吗?</em></p>
<div class="div-border-top-blue">最后一句「听说过 Python 3 吗?」是讽刺 Python 3 发布已经 8 年了,Python 社区却依然在使用 Python 2.7。而 JS 社区正好相反,把还没有实现的语言特性都用到生成环境中了!</div>
<p><br/>
<a href="https://hackernoon.com/how-it-feels-to-learn-javascript-in-2016-d3a717dd577f#.7xu075vbl" target="_blank">原文出处</a></p>网站架构演进2016-10-07T09:57:00+02:002016-10-07T09:57:00+02:00nicktag:blog.lonelylty.com,2016-10-07:/articles/2016/10/07/web-architecture-evolution/<p>网站架构的演进不外乎两个原因:</p>
<ul>
<li>用户越来越多,意味着并发要求越来越高</li>
<li>数据越来越多,意味着存储挑战越来越大</li>
</ul>
<h4>上古时代</h4>
<hr>
<p>实际上,上古时代并遥远,大概在 30 年前吧,甚至更近。那个时候上网的人很少,网站架构简单地一踏糊涂。</p>
<p><img alt="上古时代" src="/images/web_arch_the_ancient_times.png"></p>
<p>就一个数据库加一个应用服务器,应用服务器直接开门迎客。有时候,数据库和应用服务器还运行在同一台主机上,简洁得一踏糊涂。如果你认为这种架构只能做简单的事情 …</p><p>网站架构的演进不外乎两个原因:</p>
<ul>
<li>用户越来越多,意味着并发要求越来越高</li>
<li>数据越来越多,意味着存储挑战越来越大</li>
</ul>
<h4>上古时代</h4>
<hr>
<p>实际上,上古时代并遥远,大概在 30 年前吧,甚至更近。那个时候上网的人很少,网站架构简单地一踏糊涂。</p>
<p><img alt="上古时代" src="/images/web_arch_the_ancient_times.png"></p>
<p>就一个数据库加一个应用服务器,应用服务器直接开门迎客。有时候,数据库和应用服务器还运行在同一台主机上,简洁得一踏糊涂。如果你认为这种架构只能做简单的事情,那就错了。这种架构也不泛一些大型的应用场景,典型的如银行的信息系统。只是,主机要用 IBM 的大型机,数据库用 Oracle,存储器要用 EMC 。这种架构还有一个特点是贵,死贵。多年之后,一场轰轰烈烈地去 IOE 运行席卷神州大地,前期就是为了解决贵的问题,当然这是后话了。</p>
<h4>读写分离</h4>
<hr>
<p>数据库在执行写操作时,需要锁定数据表,这是为了保持数据一致性。想像一下,数据库写了一半,有人读取了数据,它读出来的数据可能是不完整的。</p>
<p>这带来的一个问题,当数据库写得比较频繁,读往往得不到执行,因为数据库老是被锁住。表现在用户层面,网速很快的情况下,一个网页显示得好久都显示不出来,这是因为数据库的读操作得不到执行。</p>
<p>读写分离就是为了解决这个问题的,核心要点是一个 Master 数据库负责数据写入,另外有一到多个 Slave 数据库负责数据读取。Master 和 Slave 之间的数据会自动同步。</p>
<p><img alt="读写分离" src="/images/web_arch_rw_sep.png"></p>
<h4>负载均衡</h4>
<hr>
<p>随着用户量越来越多,应用服务器开始忙不过来了。假设一个应用服务器可以运行 10 个 worker 线程,每个 worker 线程给用户提供服务的时间需要 10 毫秒,那么一个应用服务器只能满足 1000 次/秒的服务请求。超过了这个量级,就需要增加应用服务器,这个时候就引入了负载均衡服务器。</p>
<p>负载均衡服务器负责接收用户发过来的请求,然后看哪个应用服务器比较有空闲,就把请求发送给相应的应用服务器执行。就像部门领导一样,本身自己不做事,只负责把任务分配给空闲的工程师。</p>
<p><img alt="负载均衡" src="/images/web_arch_work_balance.png"></p>
<h4>动静分离</h4>
<hr>
<p>网站有静态内容和动态内容之分,比如我们上新浪微博网站,网站上的 Logo 就属于静态内容,它是不变的 (这里是指用户无法改变它,实际上微博的开发工程师是可以,也会改变它的),而用户发的微博属于动态内容,它是频繁改变的。用更专业的术语讲,JavaScript,CSS,网站图片属于静态内容。</p>
<p>为了进一步提高性能,可以把静态的内容和动态的内容分离,分别放在不同的服务器上。毕竟,静态的内容不需要读数据库,也不需要经过应用服务器的逻辑运算,可以直接把静态内容发送给用户。这样可以减少中间交互环节,从而提高效率。</p>
<p><img alt="动静分离" src="/images/web_arch_static_dynamic_sep.png"></p>
<h4>内容分发网络</h4>
<hr>
<p>当用户进一步增长,一个负载均衡服务器搞不定了。更要命的是,北方的用户访问速度还可以,南方的用户访问起来奇慢无比。这个时候,CDN 闪亮登场了。</p>
<p>CDN 全称是内容分发网络 (Content Delivery Network),它的原理很简单,让一个区域的用户访问那个区域的服务器。比如北方用户从青岛服务器获取数据,华南用户从杭州服务器获取数据,西南用户从广州服务器获取数据。这种分而治之的策略特别适用于静态内容。</p>
<p><img alt="内容分发网络" src="/images/web_arch_cdn.png"></p>
<p>这里有一个问题,怎么样让一部分用户从 <strong>负载均衡服务器 1</strong> 访问,另外一部分从 <strong>负载均衡服务器 2</strong> 访问?</p>
<p>这里就涉及到动态 <strong>DNS 解析</strong>的技术,我们知道普通的 DNS 解析就是从一个域名获得一个或多个对应的 IP 地址信息,这个信息是不变的,即不管是北方用户还是南方用户,获取到的信息是一样的。而动态 DNS 解析,会根据用户的 IP 地址所在的地理位置以及所处的网络运营商的拓扑结构中的位置,返回最靠近的一个 IP 地址给用户。这样就实现了用户的分流,而且实现就近访问原则,从而提高效率。</p>
<h4>数据库集群</h4>
<hr>
<p>大家看到上面的架构图,是不是有点头重脚轻的感觉?没错,单纯的读写分享已经无法满足海量数据和海量并发的需求了。这个时候,就需要大容量的分布式数据库登场了。</p>
<p><img alt="分布式数据库" src="/images/web_arch_dist_db.png"></p>
<p>分布式数据库的优点是,可以有多个数据中心,在每个数据中心都可以支持读写,后台会自动完成数据同步工作。这个在持续不间断服务领域也是个良好的应用,因为即使一个数据中心损坏了(着火,烧掉了),也可以从另外一个数据中心恢复出数据。</p>
<p>还有一个优点,当数据容量增大,需要扩容时,可以无缝扩容。即应用服务器不受影响。应用服务器只和数据库路由打交道,扩容可以在背后进行。</p>
<h4>缓存</h4>
<hr>
<p>从数据库里读数据还是慢,有没有办法把经常读的数据放在缓存里来提高效率呢?这就是 memcached, Redis 干的事情。这样演进后的架构变成了这样:</p>
<p><img alt="缓存" src="/images/web_arch_cached.png"></p>
<h4>总结</h4>
<hr>
<p>看起来很简单,很自然的演进,都是 IT 技术人员数十年努力的结果,绝不简单,绝不容易。如果和研发的开会,你要是说,不是很简单吗,加个分布式数据库不就可以解决问题么?我敢保证程序员们会在内心鄙视你,如果你不是发工资的那个人,鄙视还可能溢于言表。</p>.NET in Linux Web 服务器配置2016-07-28T14:57:00+02:002016-07-28T14:57:00+02:00nicktag:blog.lonelylty.com,2016-07-28:/articles/2016/07/28/dontnet-web-server-configuration-in-linux/<blockquote>
<h4>安装linux</h4>
</blockquote>
<p>首先我们要做的就是安装linux,其发行版redhat,ubuntu,centos等等都可以,我选择了centos.</p>
<p>1.下载 <a href="https://www.centos.org/download" target="_blank">centos</a>,安装过程这里不再赘述</p>
<p>2.服务器装好系统之后,更新系统 (耗时操作,可选择执行)</p>
<p><code>yum -y update</code> 升级所有包,改变软件设置和系统设置 …</p><blockquote>
<h4>安装linux</h4>
</blockquote>
<p>首先我们要做的就是安装linux,其发行版redhat,ubuntu,centos等等都可以,我选择了centos.</p>
<p>1.下载 <a href="https://www.centos.org/download" target="_blank">centos</a>,安装过程这里不再赘述</p>
<p>2.服务器装好系统之后,更新系统 (耗时操作,可选择执行)</p>
<p><code>yum -y update</code> 升级所有包,改变软件设置和系统设置,系统版本内核都升级</p>
<p><code>yum -y upgrade</code> 升级所有包,不改变软件设置和系统设置,系统版本升级,内核不改变</p>
<blockquote>
<h4>安装mono</h4>
</blockquote>
<p>在linux上安装mono,以便跑我们写的.net应用,另外对.net core感兴趣的同学也可以去试试,就不用装mono了,不过自己写的站点在迁移时就都要用.net core重新生成一遍了,这里有篇博文可以看看<a href="http://www.cnblogs.com/shanyou/p/4295163.html" target="_blank">http://www.cnblogs.com/shanyou/p/4295163.html</a>,个人认为目前成熟的解决方案还是mono</p>
<p><strong>1.安装Mono源码依赖库</strong></p>
<div class="highlight"><pre><span></span>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
</pre></div>
<p>可能还需要安装cmake,我在配置mono的时候遇到</p>
<p><img alt="mono依赖" src="/images/jexus/mono_config_error.png"></p>
<p><img alt="mono依赖" src="/images/jexus/mono_gcc.png"></p>
<p><strong>2.安装Mono需要的GDI+ 兼容API库 - Libgdiplus</strong></p>
<p>Libgdiplus是一个Mono库,用于对非Windows操作系统提供GDI+兼容的API。libgdiplus是mono中的System.Drawing依赖的一个组件,用于显示web页面基本颜色等。最新版本查看地址:<a href="http://download.mono-project.com/sources/libgdiplus/" target="_blank">http://download.mono-project.com/sources/libgdiplus/</a></p>
<div class="highlight"><pre><span></span>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
</pre></div>
<p><img alt="monogdi插件" src="/images/jexus/mono_gdiplus.png"></p>
<p><img alt="monogdi插件" src="/images/jexus/mono_gdi_configure.png"></p>
<p><img alt="monogdi插件" src="/images/jexus/mono_gdi_configure_summary.png"></p>
<p>Tips:</p>
<div class="highlight"><pre><span></span>tar [-cxtzjvfpPN] 文件与目录 ....
</pre></div>
<p>参数: </p>
<p>-c :建立一个压缩文件的参数指令(create 的意思); </p>
<p>-x :解开一个压缩文件的参数指令! </p>
<p>-t :查看 tarfile 里面的文件! </p>
<p>特别注意,在参数的下达中, c/x/t 仅能存在一个!不可同时存在!因为不可能同时压缩与解压缩。</p>
<p>-z :是否同时具有 gzip 的属性?亦即是否需要用 gzip 压缩? </p>
<p>-j :是否同时具有 bzip2 的属性?亦即是否需要用 bzip2 压缩? </p>
<p>-v :压缩的过程中显示文件!这个常用,但不建议用在背景执行过程! </p>
<p>-f :使用档名,请留意,在 f 之后要立即接档名喔!不要再加参数</p>
<p><strong>3.安装 mono</strong></p>
<p>最新版本查看地址:<a href="http://download.mono-project.com/sources/mono/" target="_blank">http://download.mono-project.com/sources/mono/</a></p>
<div class="highlight"><pre><span></span>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
</pre></div>
<p><img alt="mono配置" src="/images/jexus/mono_dowload.png"></p>
<p><img alt="mono配置" src="/images/jexus/mono_configure.png"></p>
<p>经过漫长的编译过程,大概需要半小时左右,输入<code>mono -V</code> 有mono版本信息,则安装成功</p>
<p><img alt="mono配置" src="/images/jexus/mono_configure_summary.png"></p>
<p>Tips:</p>
<ol>
<li>
<p>源码的安装一般由3个步骤组成:配置(configure)、编译(make)、安装(make install)</p>
</li>
<li>
<p>--prefix选项是配置安装的路径,如果不配置该选项,安装后可执行文件默认放在/usr /local/bin,库文件默认放在/usr/local/lib,配置文件默认放在/usr/local/etc,其它的资源文件放在/usr /local/share,比较凌乱</p>
</li>
</ol>
<blockquote>
<h4>安装jexus</h4>
</blockquote>
<p>选择国产的jexus作为web服务器,选这个应该是先入为主的感觉...还有就是有个 <a href="https://www.linuxdot.net/" target="_blank">linuxdotnet社区</a>,jexus配置教程和常见问题,都能在这里找到答案。把解压所得到的文件及文件夹全部复制或移动到 /usr/jexus 这个文件夹中即可</p>
<div class="highlight"><pre><span></span>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
</pre></div>
<p><img alt="jexus目录" src="/images/jexus/jexus_folder.png"></p>
<p>Tips: </p>
<p>注意安装的centos版本,centos从7.x开始默认用的是firewalld,这个是基于iptables的,虽然有iptables的核心,但是iptables的服务是没安装的,低于7的还是可以使用iptables,将80端口打开</p>
<div class="highlight"><pre><span></span>firewall-cmd --zone=public --query-port=80/tcp 查看
firewall-cmd --zone=public --add-port=80/tcp --permanent 添加 (--permanent永久生效,没有此参数重启后失效)
</pre></div>
<p>CentOS 6.x装好mono和Jexus后,在 /ect/rc.local 后面添加 /usr/jexus/jws start 就可以让jexus跟随系统一起启动,然而在CentOS 7.x上用上面的方法却行不通</p>
<div class="highlight"><pre><span></span>vi /lib/systemd/system/jexus.service
</pre></div>
<p>写入如下脚本</p>
<div class="highlight"><pre><span></span>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
</pre></div>
<p><img alt="jexus自启动" src="/images/jexus/jexus_self_start.png"></p>
<p>修改时注意服务的路径,你也可以从/lib/systemd/system 文件夹下复制一个service结尾的文件,改名后修改里面的内容。修改后 设置权限 加入到服务中去</p>
<div class="highlight"><pre><span></span>chmod 754 jexus.service
systemctl enable jexus.service
</pre></div>
<p>最后reboot看看有没有生效</p>
<blockquote>
<h4>安装nginx</h4>
</blockquote>
<p>选择nginx作为反向代理服务器,个人感觉小型站点使用这个,有点杀鸡用牛刀的赶脚,这里也不班门弄斧了,这里有个 <a href="http://www.runoob.com/linux/nginx-install-setup.html" target="_blank">教程地址</a> ,感觉写的还不错</p>
<blockquote>
<h4>结语</h4>
</blockquote>
<p>最后根据不同的业务,选择合适的数据库,whatever you want! 在这里给出linux上安装mysql<a href="http://www.runoob.com/linux/mysql-install-setup.html" target="_blank">教程地址</a>:如果是个人站点,完全可以装在同一台服务器,如果用户访问量较大,建议还是单独弄一台服务器跑数据库</p>正则速查2016-06-12T09:57:00+02:002016-06-12T09:57:00+02:00nicktag:blog.lonelylty.com,2016-06-12:/articles/2016/06/12/regex/<h5>常用元字符</h5>
<table>
<thead>
<tr>
<th>符号</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>.</td>
<td>匹配除换行符以外的任意字符。</td>
</tr>
<tr>
<td>\w</td>
<td>匹配字母或数字或下划线或汉字。</td>
</tr>
<tr>
<td>\s</td>
<td>匹配任意的空白符。</td>
</tr>
<tr>
<td>\d</td>
<td>匹配数字。</td>
</tr>
<tr>
<td>\b</td>
<td>匹配单词的开始或结束。</td>
</tr>
<tr>
<td>[ck]</td>
<td>匹配包含括号内元素的字符</td>
</tr>
<tr>
<td>^</td>
<td>匹配行的开始。</td>
</tr>
<tr>
<td>$</td>
<td>匹配行的结束。</td>
</tr>
<tr>
<td>\</td>
<td>对下一个字符转义。比如$是个特殊 的字符 …</td></tr></tbody></table><h5>常用元字符</h5>
<table>
<thead>
<tr>
<th>符号</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>.</td>
<td>匹配除换行符以外的任意字符。</td>
</tr>
<tr>
<td>\w</td>
<td>匹配字母或数字或下划线或汉字。</td>
</tr>
<tr>
<td>\s</td>
<td>匹配任意的空白符。</td>
</tr>
<tr>
<td>\d</td>
<td>匹配数字。</td>
</tr>
<tr>
<td>\b</td>
<td>匹配单词的开始或结束。</td>
</tr>
<tr>
<td>[ck]</td>
<td>匹配包含括号内元素的字符</td>
</tr>
<tr>
<td>^</td>
<td>匹配行的开始。</td>
</tr>
<tr>
<td>$</td>
<td>匹配行的结束。</td>
</tr>
<tr>
<td>\</td>
<td>对下一个字符转义。比如$是个特殊 的字符。要匹配$的话就得用\$</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<h5>反义元字符</h5>
<table>
<thead>
<tr>
<th>符号</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>\W</td>
<td>匹配任意不是字母,数字,下划线,汉字的字符。</td>
</tr>
<tr>
<td>\S</td>
<td>匹配任意不是空白符的字符。等价于 [^ \f\n\r\t\v]。</td>
</tr>
<tr>
<td>\D</td>
<td>匹配任意非数字的字符。等价于 [^0-9]。</td>
</tr>
<tr>
<td>\B</td>
<td>匹配不是单词开头或结束的位置。</td>
</tr>
<tr>
<td>[^CK]</td>
<td>匹配除了CK以外的任意字符。</td>
</tr>
</tbody>
</table>
<h5>特殊元字符</h5>
<table>
<thead>
<tr>
<th>符号</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>\f</td>
<td>匹配一个换页符。等价于 \x0c 和 \cL</td>
</tr>
<tr>
<td>\n</td>
<td>匹配一个换行符。等价于 \x0a 和 \cJ</td>
</tr>
<tr>
<td>\r</td>
<td>匹配一个回车符。等价于 \x0d 和 \cM</td>
</tr>
<tr>
<td>\t</td>
<td>匹配一个制表符。等价于 \x09 和 \cI</td>
</tr>
<tr>
<td>\v</td>
<td>匹配一个垂直制表符。等价于 \x0b 和 \cK</td>
</tr>
</tbody>
</table>
<h5>限定符</h5>
<table>
<thead>
<tr>
<th>符号</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>*</td>
<td>匹配前面的子表达式零次或多次。</td>
</tr>
<tr>
<td>+</td>
<td>匹配前面的子表达式一次或多次。</td>
</tr>
<tr>
<td>?</td>
<td>匹配前面的子表达式零次或一次。</td>
</tr>
<tr>
<td n></td>
<td>n 是一个非负整数。匹配确定的 n 次。</td>
</tr>
<tr>
<td n_="n,"></td>
<td>n 是一个非负整数。至少匹配n 次。</td>
</tr>
<tr>
<td n_m="n,m"></td>
<td>m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。</td>
</tr>
</tbody>
</table>
<h5>懒惰限定符</h5>
<table>
<thead>
<tr>
<th>符号</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>*?</td>
<td>重复任意次,但尽可能少重复。<br> 如 "acbacb" 正则 "a.*?b" 只会取到第一个"acb" 原本可以全部取到但加了限定符后,<br>只会匹配尽可能少的字符 ,而"acbacb"最少字符的结果就是"acb" 。</td>
</tr>
<tr>
<td>+?</td>
<td>重复1次或更多次,但尽可能少重复。与上面一样,只是至少要重复1次。</td>
</tr>
<tr>
<td>??</td>
<td>重复0次或1次,但尽可能少重复。如 "aaacb" 正则 "a.??b" 只会取到最后的三个字符"acb"。</td>
</tr>
<tr>
<td n_m="n,m"></td>
<td 0_m="0,m">重复n到m次,但尽可能少重复。如 "aaaaaaaa" 正则 "a</td>
</tr>
<tr>
<td n_="n,"></td>
<td 1_="1,">重复n次以上,但尽可能少重复。如 "aaaaaaa" 正则 "a</td>
</tr>
</tbody>
</table>
<h5>捕获分组</h5>
<table>
<thead>
<tr>
<th>符号</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>(exp)</td>
<td>匹配exp,并捕获文本到自动命名的组里。</td>
</tr>
<tr>
<td>(?<name>exp)</td>
<td>匹配exp,并捕获文本到名称为name的组里。</td>
</tr>
<tr>
<td>(?:exp)</td>
<td>匹配exp,不捕获匹配的文本,也不给此分组分配组号以下为零宽断言。</td>
</tr>
<tr>
<td>(?=exp)</td>
<td>匹配exp前面的位置。<br>如 "How are you doing" 正则"(?<txt>.+(?=ing))" 这里取ing前所有的字符,<br>并定义了一个捕获分组名字为 "txt" 而"txt"这个组里的值为"How are you do";</td>
</tr>
<tr>
<td>(?<=exp)</td>
<td>匹配exp后面的位置。<br>如 "How are you doing" 正则"(?<txt>(?<=How).+)" 这里取"How"之后所有的字符,<br>并定义了一个捕获分组名字为 "txt" 而"txt"这个组里的值为" are you doing";</td>
</tr>
<tr>
<td>(?!exp)</td>
<td 3>匹配后面跟的不是exp的位置。如 "123abc" 正则 "\d</td>
</tr>
<tr>
<td>(?<!exp)</td>
<td>匹配前面不是exp的位置。<br>如 "abc123 " 正则 "(?<![0-9])123" 匹配"123"前面是非数字的结果也可写成"(?!<\d)123"</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>牛刀小试一下下,常用正则Query封装</strong></p>
</blockquote>
<div class="highlight"><pre><span></span><span class="kd">var</span> <span class="nx">regex</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">regex</span> <span class="o">||</span> <span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="nx">$</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">_reg</span> <span class="o">=</span> <span class="p">{};</span>
<span class="cm">/* 'pwd':/^[\@A-Za-z0-9\!\#\$\%\^\&\*\.\~]{6,16}$/,//密码 */</span>
<span class="c1">//验证数字</span>
<span class="nx">$</span><span class="p">.</span><span class="nx">extend</span><span class="p">(</span><span class="nx">_reg</span><span class="p">,</span> <span class="p">{</span>
<span class="s1">'num'</span><span class="o">:</span> <span class="sr">/^\d+$/</span><span class="p">,</span> <span class="c1">//数字</span>
<span class="s1">'znum'</span><span class="o">:</span> <span class="sr">/^[1-9](\d+)?$/</span><span class="p">,</span> <span class="c1">// 大于0的数字</span>
<span class="s1">'float'</span><span class="o">:</span> <span class="sr">/^[-]{0,1}(\d+)[\.]+(\d+)$/</span><span class="p">,</span> <span class="c1">//浮点数</span>
<span class="s1">'money'</span><span class="o">:</span> <span class="sr">/^\d{1,12}(?:\.\d{1,3})?$/</span><span class="p">,</span> <span class="c1">// money</span>
<span class="s1">'idCard'</span><span class="o">:</span> <span class="sr">/^\d{15}$|^\d{18}$|^\d{17}[xX]$/</span><span class="p">,</span> <span class="c1">//身份证</span>
<span class="s1">'idCardStrict'</span><span class="o">:</span><span class="sr">/^(\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})$/</span><span class="p">,</span>
<span class="s1">'qq'</span><span class="o">:</span> <span class="sr">/^[1-9]\d{4,15}$/</span><span class="p">,</span> <span class="c1">//QQ</span>
<span class="s1">'pwd'</span><span class="o">:</span> <span class="sr">/^[\@A-Za-z0-9]{6,16}$/</span><span class="p">,</span> <span class="c1">//密码</span>
<span class="s1">'areacode'</span><span class="o">:</span> <span class="sr">/^(0[1,2]{1}\d{1})$|^(0[3-9]{1}\d{2})$/</span><span class="p">,</span> <span class="c1">//区号</span>
<span class="s1">'tel'</span><span class="o">:</span> <span class="sr">/^\d{7,8}$/</span><span class="p">,</span> <span class="c1">// 固话格式</span>
<span class="s1">'mobile'</span><span class="o">:</span> <span class="sr">/^((\+86)|(\(\+86\)))?-?(13|14|15|18|17)[0-9]{9}$/</span><span class="p">,</span> <span class="c1">//验证手机号码</span>
<span class="s1">'telephone'</span><span class="o">:</span> <span class="sr">/^(((\+)?86)|(\(\+86\)))?-?((((0)?[1,2]{1}\d{1})?-?\d{8})|((0[3-9]{1}\d{2})?-?\d{7,12}))-?(\d{1,8})?$/</span><span class="p">,</span> <span class="c1">//验证固定电话</span>
<span class="s1">'phone'</span><span class="o">:</span> <span class="sr">/^((\+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}))$/</span><span class="p">,</span> <span class="c1">//手机号码和固定电话</span>
<span class="s1">'zipcode'</span><span class="o">:</span> <span class="sr">/^\d{6}$/</span> <span class="c1">//验证邮编</span>
<span class="p">});</span>
<span class="c1">//验证字符串</span>
<span class="nx">$</span><span class="p">.</span><span class="nx">extend</span><span class="p">(</span><span class="nx">_reg</span><span class="p">,</span> <span class="p">{</span>
<span class="s1">'email'</span><span class="o">:</span> <span class="sr">/^\w{1,16}([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/</span><span class="p">,</span> <span class="c1">//邮箱</span>
<span class="s1">'chinese'</span><span class="o">:</span> <span class="sr">/^[\u4E00-\u9FA5]+$/</span><span class="p">,</span> <span class="c1">//仅汉字</span>
<span class="s1">'char'</span><span class="o">:</span> <span class="sr">/^[A-Za-z]+$/</span><span class="p">,</span> <span class="c1">//仅仅是字母</span>
<span class="s1">'charn'</span><span class="o">:</span> <span class="sr">/^[A-Za-z0-9]+$/</span><span class="p">,</span> <span class="c1">//数字加字母</span>
<span class="s1">'nospecial'</span><span class="o">:</span> <span class="sr">/^[\u4E00-\u9FA5A-Za-z0-9]+$/</span><span class="p">,</span> <span class="c1">// 不包含特殊字符</span>
<span class="s1">'url'</span><span class="o">:</span> <span class="sr">/^((http|https|ftp):\/\/)?(\w(\:\w)?@)?([0-9a-z_-]+\.)*?([a-z0-9-]+\.[a-z]{2,6}(\.[a-z]{2})?(\:[0-9]{2,6})?)((\/[^?#<>\/\\*":]*)+(\?[^#]*)?(#.*)?)?$/</span><span class="p">,</span>
<span class="s1">'loginName'</span><span class="o">:</span> <span class="sr">/^(13|14|15|18|17)[0-9]{9}$|^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/</span><span class="p">,</span> <span class="c1">// 用户名</span>
<span class="s1">'userName'</span><span class="o">:</span> <span class="sr">/^[\u4e00-\u9fa5]{2`,4}$|[a-zA-Z]{4,20}$/</span><span class="p">,</span> <span class="c1">//真实姓名</span>
<span class="s1">'nickName'</span><span class="o">:</span> <span class="sr">/^([a-zA-Z\u4e00-\u9fa5]{1}[a-zA-Z0-9_\u4e00-\u9fa5]{3,19})$/</span> <span class="c1">//昵称</span>
<span class="p">});</span>
<span class="k">return</span> <span class="nx">_reg</span><span class="p">;</span>
<span class="p">})(</span><span class="nb">document</span><span class="p">,</span> <span class="nb">window</span><span class="p">.</span><span class="nx">jQuery</span><span class="p">);</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">regex</span> <span class="o">=</span> <span class="nx">regex</span><span class="p">;</span>
</pre></div>Markdown 11种基本语法2016-05-31T16:57:00+02:002016-05-31T16:57:00+02:00nicktag:blog.lonelylty.com,2016-05-31:/articles/2016/05/31/markdown/<h5>1. 标题设置(让字体变大,和word的标题意思一样)</h5>
<p>在Markdown当中设置标题,有两种方式:
第一种:通过在文字下方添加“=”和“-”,他们分别表示一级标题和二级标题。
第二种:在文字开头加上 “#”,通过“#”数量表示几级标题。(一共只有1~6级标题,1级标题字体最大)</p>
<h5>2. 块注释(blockquote …</h5><h5>1. 标题设置(让字体变大,和word的标题意思一样)</h5>
<p>在Markdown当中设置标题,有两种方式:
第一种:通过在文字下方添加“=”和“-”,他们分别表示一级标题和二级标题。
第二种:在文字开头加上 “#”,通过“#”数量表示几级标题。(一共只有1~6级标题,1级标题字体最大)</p>
<h5>2. 块注释(blockquote)</h5>
<p>通过在文字开头添加“>”表示块注释。(当>和文字之间添加五个blank时,块注释的文字会有变化。)</p>
<h5>3. 斜体</h5>
<p>将需要设置为斜体的文字两端使用1个“*”或者“_”夹起来</p>
<h5>4. 粗体</h5>
<p>将需要设置为斜体的文字两端使用2个“*”或者“_”夹起来</p>
<h5>5. 无序列表</h5>
<p>在文字开头添加(<em>, +, and -)实现无序列表。但是要注意在(</em>, +, and -)和文字之间需要添加空格。(建议:一个文档中只是用一种无序列表的表示方式)</p>
<h5>6. 有序列表</h5>
<p>使用数字后面跟上句号。(还要有空格)</p>
<h5>7. 链接(Links)</h5>
<p>Markdown中有两种方式,实现链接,分别为内联方式和引用方式。</p>
<p>内联方式:This is an <a href="http://example.com/">example link</a>.
引用方式:
I get 10 times more traffic from <a href="http://google.com/" title="Google">Google</a> than from <a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/" title="MSN Search">MSN</a>. </p>
<h5>8. 图片(Images)</h5>
<p>图片的处理方式和链接的处理方式,非常的类似。
内联方式:<img alt="alt text" src="/path/to/img.jpg" title="Title">
引用方式:<img alt="alt text" src="/path/to/img.jpg" title="Title"> </p>
<h5>9. 代码(HTML中所谓的Code)</h5>
<p>实现方式有两种:
第一种:简单文字出现一个代码框。使用<code><blockquote></code>。(<code>不是单引号而是左上角的ESC下面~中的</code>)
第二种:大片文字需要实现代码框。使用Tab和四个空格。</p>
<h5>10. 脚注(footnote)</h5>
<p>实现方式如下:
hello[^hello]</p>
<h5>11. 下划线</h5>
<p>在空白行下方添加三条“-”横线。(前面讲过在文字下方添加“-”,实现的2级标题)</p>
<p><a href="https://stackedit.io/">推荐一款在线的Markdown编辑器</a> </p>