单页WEB应用(九),终篇-总结和发布

来源:互联网 发布:linux shell 参数 编辑:程序博客网 时间:2024/05/21 17:30

前言

本篇是该书系列最后一篇,本书所有涉及的功能和其中所涉及的知识点,基本已经学习完成。

大体上有以下几个部分

  1. 简单的页面布局

    第一个部分首先是进行简单的页面,和其布局的设计,并且采用的是模块化思想,组件组装器概念,因此每个模块都有自己的页面代码,在加载模块的时候将其渲染出来。

  2. 功能添加和功能容器,或者说模块容器及其子模块

    这部分主要涉及,模块容器 shell 和页面子模块的完成,这部分主要值得学习的是该单页应用的实现思想,即组件组装器概念:也就是将 shell 定义成全局的容器作用,在该容器中负责着子组件的加载和初始化行为,而子组件的功能实现被限定在自身模块当中,从而不会与其他模块产生混淆,降低了模块与模块之间的依赖性;

  3. 数据模型模块

    这部分主要负责数据模型的创建和管理,比如(用户管理对象 peoplechat 聊天消息对象等等),而数据模块负责对该应用涉及到的数据的增删改查等功能的实现。

  4. 服务器

    如果说前面几个部分都属于客户端一块的东西,那这以及这以后的部分则是涉及到服务器端的业务和功能的内容了,该应用的服务器部分自然由 Node.js 来承担,而其中涉及的路由、通信、数据库则是由 expresssocket.io,和 mongodb 等来完成,并且在后台服务器的处理过程中,还涉及了一些认证,数据验证,CRUD 等概念。

经过该书的系统性学习加实践,对于单页应用的大体开发流程,和其中涉及的部分关键技术有了更深的认识,其中也对部分关键技术做了更深入的研究,比如(Node.jsexpresssocket.iomongodb),并且在该书系列完成之后便会依次完整系统性的去学习这些知识点。

知识点回顾

模块化思想

模块化实现,不仅让功能进行分离,减少模块间的依赖,还可使代码更容易维护,甚至能使模块得到复用,好处自然是值得称赞。

比如当前主流的模块化编程有(CommonJSAMDCMDES6 标准),这里简单看下它们的简单使用方式,稍详细点的介绍,之前有篇文章是关于这几个的,地址:WEB前端模块化基础知识 go ✈

  • CommonJS

    相对而言,CommonJS 模块化更偏向于服务器端,也正由于它的发展就是由服务器端模块化的需要,随着技术不断更新和发展,前端模块化的概念推出,CommonJSNode.js的推动下大力支持了前端模块化。

    // welcome.jsvar hello = 'hello world!';function sayHello () {    alert( hello );}function bye() {    alert( 'bye bye !' );}module.exports = {    hello   : sayHello,    bye     : bye}

    使用:

    // test.jsvar welcome = require( './welcome' );welcome.hello();    // 'hello world!'welcome.bye();      // 'bye bye !'
  • AMD

    AMD:Asynchronous Module Definition,异步模块定义,属于异步加载,这个其实是一套基于浏览器模块化开发的规范,要使用该规范进行模块化开发,需要用到其中的函数库:requireJS

    相比较 CMD 而言,这个有个不好的地方就是,模块需要提前一次性进行加载。

    来看下器定义和使用:

    定义:

    // module.jsdefine(    ['dependModule1', 'dependModule2', ...],  // 这个数组里面包含了该模块所依赖的所有模块    function () {        // 这里面就是新模块的内容        return {            // 返回模块对象        };    });

    会发现上面模块的定义时,define 中并没有声明模块的名称,这是因为对于 AMD 而言,一个文件既是一个模块,因此该模块的文件名也就是该模块的名称:module

    使用:

    // test.js// 加载模块require(['module'], function ( myModule ) {    // myModule 就是模块加载完成之后,该模块的对象名,在这个回调里面    // 可以通过 myModule 来引用该模块});
  • CMD

    CMD:Common Module Definition,表示通用模块定义,这个相对 AMD 有个好处就是,能按需加载模块,也就是说在哪里需要才去加载模块,而不是一次性把模块全部加载好,这点会一定程度上减少程序启动时间,但在运行过程中则需要实时去加载模块。

    定义:

    // module.jsdefine(function (require, exports, module) {    var dependModule = require( 'dependModuleName.js' );    // balabala  module content});

    使用模块,需要用到 seajs

    seajs.use(['module.js'], function (myModule) {    // 模块加载完成});
  • ES6

    ES6 标准下的模块化编程,主要分两种方式

    1. 命名式导出

      这种方式,支持一个文件同时可以导出多个函数或变量

      比如:

      // module.jsexport function fn1() {}export var1 = 10;

      然后通过 import 使用:

      // test.jsimport { fn1, var1 } from 'module'// 或者别名import { fn1, var1 } as myModule from 'module'// 或者import { fn1 as show, var1 as name } from 'module'
    2. 定义式导出

      定义式导出,一个文件只能出现一个定义式的导出变量或函数

      比如:

      // module.js// 这个时候就可以省略调函数名export function () {}

      使用的时候,可以通过文件名,或者 default 关键字来使用 module.js 模块中定义式声明的函数,因为一个文件只需要一个,因此不用担心会引用不对的情况发生

      // test.jsimport myModule from 'module';// 或者使用 defaultimport default from 'module';// 也可别名import { default as myModule } from 'module';
    3. 混合使用

      也就是说两种定义方式可以混合使用。

      // module.jsexport function () {    // 定义式导出方式的内容 在这里完成}// 下面是命名式方式export function fn1() {}export function fn2() {}export var name = 'lizc';

      使用:

      // test.js// 这里的 module 可以用 default 代替,得到的结果就是 // module.js 中采取定义式方式定义的那个函数import { module, fn1, fn2, name } from 'module'

服务器端编程

该书中的单页应用中的服务器端是基于 Node.js 来实现的,其中使用到的内容主要包含三大块(ExpressSocket.IOMongoDB)下面依次来简单的回顾下

  • http 服务器

    先来看下使用 http 模块创建简单的服务器

    // server.jsrequire( 'http' ).createServer(function ( req, res ) {    // do something}).listen( 3000 );
  • Express

    使用 express 创建服务器程序

    // server.jsvar express = require( 'express' )    app = express();app.listen( 3000, function () {    console.log( 'express server listening on port 3000.' );} );

    httpexpress 混合使用的情况

    // server.jsvar http    = require( 'http' ),    express = require( 'express' ),    app     = express(),    server;server = http.createServer( app );server.listen( 3000, function () {    console.log( 'http server with express listening on port 3000.' );} );

    express 环境变量(’development’, ‘testing’, ‘staging’, ‘production’)

    获取: app.get( 'env' );

    设置: app.set( 'env', 'testing' );

    中间件使用:比如日志中间件(logger)

    在 3.0+ 版本中 logger 可直接通过 express.logger 使用,4.0+ 版本中大部分中间件都被独立出来了,都需要单独安装使用

    安装 logger: npm install morgan --save, 4.0+ 中间件 logger 的包名是:morgan

    使用: `app.use( logger( ‘dev’ ) );

    可以根据开发环境不同设置不同的中间件

    比如:

    var env = app.get( 'env' );if ( env === 'development' ) {    app.use( ... );} else if ( env === 'testing' ) {    app.use( ... );}......

    自定义中间件

    app.use( function ( req, res, next ) {    // 中间件处理程序    next();} );

    路由设置

    get 请求路由处理:

    app.get( '/', function ( req, res ) { ...... } );

    post 请求路由处理:

    app.post( '/', function ( req, res ) { ...... } );

    通用路由处理(必须要有 next 且执行 next(); 将路由控制流往下传递)

    app.all( '/', function ( req, res, next ) { ...... } );

  • Socket.IO

    socket.io 主要用来客户端和服务器进行通信用,通过消息加事件触发机制来完成。

    要使用 socket.io ,首先要建立个服务器,如上面 httpexpress 方式,然后获取 socket 实例监听该服务器,得到通信管道。

    // server.jsvar http    = require( 'http' ),    express = require( 'express' ),    app     = express(),    socket  = require( 'socket.io' ),    server, io;// 新建服务server = http.createServer( app );// socket 监听服务io = socket.listen( server );// 服务监听端口 3000server.listen( 3000, function () {    console.log( 'http server with express listening on port 3000.' );} );

    服务程序创建完成,并且使用 socket 进行了监听,那么接下来就可以通过 socket 管道向客户端发送消息:

    io.sockets.emit( 'update', data );

    客户端通过连接,然后监听消息

    前提:客户端需要通过 <script> 引入 socket.io 库文件

    <script src="/socket.io/socket.io.js"></script>

    接下来就可以 :

    var connect = io.connect( 'http://192.168.179.103:3000' );// 开始监听消息connect.on( 'update', function ( data ) {    // 这里就是客户端对服务器发送来的 update 消息的处理程序    // 参数 data 就是服务器携带的数据} );

    也可以链式写法:

    io.connect( 'http://192.168.179.103:3000' ).on( 'update', function ( data ) {    // 这里就是客户端对服务器发送来的 update 消息的处理程序    // 参数 data 就是服务器携带的数据} );

    上面就是个简单的 socket.io 客户端和服务器连接,以及消息的发送和监听处理。

  • MongoDB

    数据库,基于文件存储,文件内容,采用的是 JSON 格式,也就是说该数据库的数据存储包括各种操作都是在 JSON 之上进行的。对于更多的介绍和优缺点,百度/google/官网介绍的很详细,没事可以去观摩观摩。

    这里就直接回顾下它的简单使用

    首先:安装

    sudo apt-get install -y mongodb-org

    安装之后,需要启动下服务,不然直接使用 mongo 进入数据库时候会报错。

    sudo service start mongod

    启动之后就可以进入 mongo 数据库的命令行进行数据库操作了,这里就不回顾了,重点是 Node.js 环境下 mongodb 的使用。

    在新版 2.0+ 中,连接方式已经发生了改变,使用如下:

    // 引入数据库模块,并获取数据库实例var MongoClient = require( 'mongodb' ).MongoClient,    collection;// 连接到默认的 test 数据库MongoClient.connect( 'mongodb://localhost:27017/test', function ( error, db ) {    // 这个函数有两个参数,第一个表示连接过程中发生的错误对象,如果    // 该对象存在,表示连接不成功,可以通过该对象获取到具体错误信息    // 只有在 error 为空的情况下,表示连接成功,那么第二个参数 db 就是连接后的数据库实例    // 通过这个实例我们就可以连接到 test 数据库中具体集合对象,比如:user    collection = db.collection( 'user' );    // 随后就可以对集合进行一系列的 CRUD 操作} );

    CRUD 相关函数(需要注意的是这些函数都是基于数据中集合上进行操作的)

    插入:

    collection.insertOne({}, function ( error, result ) {} );

    collection.insertMany([{},{}], function ( error, result ) {} );

    error: 插入失败的错误信息;
    result:插入之后的结果,一般包含插入的条目,简要内容等信息;

    删除:

    collection.deleteOne( {}, function ( error, result ) {} );

    collection.deleteMany( [{},{}], function ( error, result ) {} );

    更新:

    collection.updateOne( find_map, set_map, function ( error, result ) {} );

    collection.updateMany( find_map, { $set: set_map }, function ( error, result ) {} );

    find_map:查找的对象,需要被更新的;
    set_map: 更新的对象,用来替换旧数据的;

    查找:查找功能很强大,并且包含很多功能,具体可参考 find链式函数

    collection.find( {}, function ( error, result ) {} );

  • 通过路由和数据库结合,返回查询结果

    // 路由处理app.get( '/user/list', function ( req, res ) {    // 查询所有用户    collection.find( {} ).toArray( function ( error, result ) {        // 错误退出        if ( error ) { return false; }        // 成功返回查询到的的结果        // 回调放在 toArray 中,表示将结果数组化        res.send( result );    } );} );

发布准备

最后来看下该书对于发布的准备工作都讲了些啥

前面部分讲述了爬虫,错误处理机制,CDN,重点看下缓存的内容。

缓存

缓存方式有下面四种:

  1. Web 存储:把字符串保存至客户端,应用可以访问这些数据,并用它来保存处理好的 HTML,这些HTML是根据服务器上的数据生成的;

    包含两种方式:本地存储(localStorage)和会话存储(sessionStorage)

    两种方式除了存储时期不同之外,使用方式几乎相同

    window.storage = localStorage || sessionStorage;

    对象的使用方式也有两种,通过 *item 系的函数,或者直接使用 obj[ key ] = value 形式,推荐使用函数方式;

    添加:

    storage.setItem(key, value);storage[ key ] = value;

    读取:

    storage.getItem( key );storage[ key ];

    修改:

    storage.setItem(key, newValue);

    删除:

    storage.removeItem( key );

  2. HTTP 缓存:客户端缓存,在客户端保存着服务器的响应;

    这种方式是通过浏览器进行缓存,当服务器给浏览器发送数据时,这个时候浏览器就会把数据缓存起来,下次如果发生同样的数据请求时直接从浏览器缓存中读取。

    对于 HTTP 缓存有两种模式存储:是否检查数据新鲜度(或者说是否过期)

    如果不检查,相当于直接取浏览器缓存;
    如果检查,则需要从服务器重新获取数据;

    因此 HTTP 缓存方式比较适合那种在一定时间内不会有啥改动的数据,比如图片,脚本文件,样式文件等等。

    max-age

    服务器在响应数据的时候,可以通过设置 max-age 来告诉客户端该数据需要被缓存多久,设置方式:
    单位(秒),如果设为 0 ,表示每次请求都需要检查数据是否是最新的。

    res.header( 'Cache-Control', 'max-age=28800' );

    阻止中间服务器使用它的缓存,可以通过下面三个属性来达到目的:

    • no-cache: 不进行缓存,使用起来会引起不必要的慢,建议使用 no-store
    • no-store:通知客户端和中间服务器,不缓存本次请求结果;
    • last-modified:在不设置 Cache-Control 情况下,客户端会根据这个属性来决定缓存期限,通常是这个值的 1/3;
  3. 服务器缓存:Memcached 和 Redis 服务器缓存,将客户端请求的响应数据保存至服务器,以至于其他请求同样的数据的时候可以使用,而不用重新搜索数据库;

  4. 数据库缓存:数据库缓存查询结果,供下次使用。

把书中的对比图绘制了一份,看下图更直观

缓存机制

结篇语

《单页应用开发》这本书完整的阅读下来,包括一步步跟着把书中代码敲下来,至今刚好一个月了,这本书中从前到后的介绍了单页应用的开发过程,从中学习到了很多内容,不管是编程思想上,还是技术知识上都是不小的积累。

还是随便侃几句吧,文笔太菜了,只怪书读的太少,囧!

学习的步伐越来越紧促,越是感觉知识的缺乏,技术的薄弱,不论以往经历了什么,如今能继续从事自己热爱的技术工作,是件值得开心的事情,前路漫漫,奋斗在路上 !!!

最后感谢作者,也感谢翻译此书的牛牛们!

0 0
原创粉丝点击