# 性能优化实战(二)

没分段,后面补

之前的面向对象的server告一段落,采用ioc的方式进行内容注入

先将app.js中 的路由注入删掉

import 'module-alias/register';
import Koa from 'koa';
const app = new Koa();
import config from '@config';
import render from 'koa-swig';
import { wrap } from 'co';
import serve from 'koa-static';
import errorHandler from "./middlewares/errorHandler";
const { error } = errorHandler;
import { configure, getLogger } from 'log4js';
const { viewDir, staticDir, port, cache } = config;
configure({
    appenders: { cheese: { type: 'file', filename: __dirname + '/logs/yd.log' } },
    categories: { default: { appenders: ['cheese'], level: 'error' } }
});
const logger = getLogger('cheese');
app.context.logger = logger;
app.context.render = wrap(render({
    root: viewDir,
    autoescape: true,
    cache,
    ext: 'html',
    writeBody: false
}))
app.use(serve(staticDir));
error(app);
// -------------------被删了---------------------------
// 路由的注册中心
// controllersInit(app);
app.listen(port, () => {
    console.log('服务启动成功!!');
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

然后BooksController.js中的model也删掉

import cheerio from 'cheerio';
import {Readable} from 'stream';

class BookController {
    async actionIndex(ctx, next) {
        ctx.status = 200;
        ctx.type = 'html';
        const result = await $model.getList();
        const html = await ctx.render('books/pages/list', {
            result
        });
        if(ctx.request.header["x-pjax"]){
            console.log('站内切');
            const $ = cheerio.load(html);
            // let _result = '';
            $('.pjaxcontent').each(function() {
                ctx.res.write($(this).html());
            })
            $('.lazyload-js').each(function() {
                ctx.res.write(`<script src="${$(this).attr("src")}"></script>`);
            })
            // ctx.body = _result;
            ctx.res.end();
        } else {
            // console.log('直接刷新');
            // ctx.body = html;
            function createSSRStream() {
                return new Promise((resolve, reject) => {
                    const htmlStream = new Readable();
                    htmlStream.push(html);
                    htmlStream.push(null);
                    htmlStream.on('error',err => {reject(err)}).pipe(ctx.res);
                })
            }
            await createSSRStream();
        }
        // console.log("返回的值", result);
        // ctx.body = html;
    }
    async actionCreate(ctx, next) {
        ctx.body = await ctx.render('books/pages/create');
    }
}

export default BookController;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

controllers中没用的index.js和BaseController.js也可以删掉了

安装两个包

yarn add awilix awilix-koa
1

在app.js中进行注入

import 'module-alias/register';
import Koa from 'koa';
const app = new Koa();
import config from '@config';
import render from 'koa-swig';
import { wrap } from 'co';
import serve from 'koa-static';
import errorHandler from "./middlewares/errorHandler";
const { error } = errorHandler;
import { configure, getLogger } from 'log4js';
const { viewDir, staticDir, port, cache } = config;
import { createContainer, Lifetime } from 'awilix';
import { loadControllers, scopePerRequest } from 'awilix-koa';

// 构建容器
const container = createContainer();
container.loadModules([__dirname + ["/services/*.js"]], {
    resolverOptions: {
        lifetime: Lifetime.SCOPED
    }
})
// 把容器和路由最终合并到一起
app.use(scopePerRequest(container));

configure({
    appenders: { cheese: { type: 'file', filename: __dirname + '/logs/yd.log' } },
    categories: { default: { appenders: ['cheese'], level: 'error' } }
});
const logger = getLogger('cheese');
app.context.logger = logger;
app.context.render = wrap(render({
    root: viewDir,
    autoescape: true,
    cache,
    ext: 'html',
    writeBody: false
}))
app.use(serve(staticDir));
error(app);
// 加载所有的路由
loadControllers(__dirname + '/controllers/*.js');
app.listen(port, () => {
    console.log('服务启动成功!!');
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

把 modle文件夹改名为 services,Books改名为 BooksServices.js

在 controllers/BooksController.js中添加注入

import cheerio from 'cheerio';
import {Readable} from 'stream';

class BookController {
    // -----------------------------------
    constructor({booksServices}) {
        this.booksServices = booksServices;
    }
    // -----------------------------------
    async actionIndex(ctx, next) {
        ctx.status = 200;
        ctx.type = 'html';
        // -----------------------------------
        const result = await this.booksServices.getList();
        // -----------------------------------
        const html = await ctx.render('books/pages/list', {
            result
        });
        if(ctx.request.header["x-pjax"]){
            console.log('站内切');
            const $ = cheerio.load(html);
            // let _result = '';
            $('.pjaxcontent').each(function() {
                ctx.res.write($(this).html());
            })
            $('.lazyload-js').each(function() {
                ctx.res.write(`<script src="${$(this).attr("src")}"></script>`);
            })
            // ctx.body = _result;
            ctx.res.end();
        } else {
            // console.log('直接刷新');
            // ctx.body = html;
            function createSSRStream() {
                return new Promise((resolve, reject) => {
                    const htmlStream = new Readable();
                    htmlStream.push(html);
                    htmlStream.push(null);
                    htmlStream.on('error',err => {reject(err)}).pipe(ctx.res);
                })
            }
            await createSSRStream();
        }
        // console.log("返回的值", result);
        // ctx.body = html;
    }
    async actionCreate(ctx, next) {
        ctx.body = await ctx.render('books/pages/create');
    }
}

export default BookController;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

再在app.js中

import 'module-alias/register';
import Koa from 'koa';
const app = new Koa();
import config from '@config';
import render from 'koa-swig';
import { wrap } from 'co';
import serve from 'koa-static';
import errorHandler from "./middlewares/errorHandler";
const { error } = errorHandler;
import { configure, getLogger } from 'log4js';
const { viewDir, staticDir, port, cache } = config;
// --------------------------------------------------------
import { createContainer, Lifetime } from 'awilix';
import { loadControllers, scopePerRequest } from 'awilix-koa';

// 构建容器
const container = createContainer();
container.loadModules([__dirname + ["/services/*.js"]], {
// --------------------------------------------------------
    formatName: 'camelCase',
// --------------------------------------------------------
    resolverOptions: {
        lifetime: Lifetime.SCOPED
    }
})
// 把容器和路由最终合并到一起
app.use(scopePerRequest(container));
// --------------------------------------------------------
configure({
    appenders: { cheese: { type: 'file', filename: __dirname + '/logs/yd.log' } },
    categories: { default: { appenders: ['cheese'], level: 'error' } }
});
const logger = getLogger('cheese');
app.context.logger = logger;
app.context.render = wrap(render({
    root: viewDir,
    autoescape: true,
    cache,
    ext: 'html',
    writeBody: false
}))
app.use(serve(staticDir));
error(app);
// 加载所有的路由
app.use(loadControllers(__dirname + '/controllers/*.js'));

app.listen(port, () => {
    console.log('服务启动成功!!');
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

到此就完成了依赖注入

接下来添加路由 BooksController.js

import cheerio from 'cheerio';
import {Readable} from 'stream';
// ---------------------------------------
import {route, GET} from 'awilix-koa';
// ---------------------------------------
@route('/books')
class BookController {
    constructor({booksServices}) {
        this.booksServices = booksServices;
    }
    // ---------------------------------------
    @route('/list')
    @GET()
    // ---------------------------------------
    async actionIndex(ctx, next) {
        ctx.status = 200;
        ctx.type = 'html';
        const result = await this.booksServices.getList();
        const html = await ctx.render('books/pages/list', {
            result
        });
        if(ctx.request.header["x-pjax"]){
            console.log('站内切');
            const $ = cheerio.load(html);
            // let _result = '';
            $('.pjaxcontent').each(function() {
                ctx.res.write($(this).html());
            })
            $('.lazyload-js').each(function() {
                ctx.res.write(`<script src="${$(this).attr("src")}"></script>`);
            })
            // ctx.body = _result;
            ctx.res.end();
        } else {
            // console.log('直接刷新');
            // ctx.body = html;
            function createSSRStream() {
                return new Promise((resolve, reject) => {
                    const htmlStream = new Readable();
                    htmlStream.push(html);
                    htmlStream.push(null);
                    htmlStream.on('error',err => {reject(err)}).pipe(ctx.res);
                })
            }
            await createSSRStream();
        }
        // console.log("返回的值", result);
        // ctx.body = html;
    }
    // ---------------------------------------
    @route('/create')
    @GET()
    // ---------------------------------------
    async actionCreate(ctx, next) {
        ctx.body = await ctx.render('books/pages/create');
    }
}

export default BookController;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

IndexController.js

import Controller from './BaseController';
const fs = require('fs');
const {resolve} = require('path');
import {route, GET} from 'awilix-koa';

@route('/')
class IndexController extends Controller{
    constructor() {
        super()
    }
    @route('/')
    @GET()
    async actionIndex(ctx, next) {
        // ctx.body = await ctx.render('Index/index')
        ctx.body = {
            home: '首页数据'
        }
    }
    @route('/test')
    @GET()
    async testIndex(ctx, next) {
        ctx.status = 200;
        ctx.type = 'html';
        const task1 = () => {
            return new Promise((resolve, reject) => {
                setTimeout(function() {
                    resolve(`<script>addHTML("part1", "第一次输出<br/>")</script>`)
                }, 1000);
            })
        }
        const task2 = () => {
            return new Promise((resolve, reject) => {
                setTimeout(function() {
                    resolve(`<script>addHTML("part2", "第二次输出<br/>")</script>`)
                }, 2000);
            })
        }
        const filename = resolve(__dirname, 'index.html');
        const file1 = fs.readFileSync(filename ,'utf-8');
        // ctx.body = file1;
        // ctx.res.write(file1);
        // ctx.res.end();
        /* function createSSRStream() {
            return new Promise((resolve, reject) => {
                const stream = fs.createReadStream(filename);
                stream.on('data', chunk => {ctx.res.write(chunk)});
                stream.on('end', () => {
                    ctx.res.end();
                })
                stream.on('error',err => {reject(err)});
            })
        }
        await createSSRStream(); */
        ctx.res.write(file1);
        const result1 = await task1();
        ctx.res.write(result1);
        const result2 = await task2();
        ctx.res.write(result2);
        ctx.res.end();
    }
}
export default IndexController;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

此时打包报错,gulp不支持装饰器 再装个装饰器的插件

yarn add @babel/plugin-proposal-decorators
1

修改 gulpfile 文件

const gulp = require('gulp');
const watch = require('gulp-watch');
const babel = require('gulp-babel');
const entry = './src/server/**/*.js';
const configEntry = './src/server/config/index.js';
const rollup = require('gulp-rollup');
const replace = require('rollup-plugin-replace');
// 开发环境
function builddev() {
    return watch(entry, {ignoreInitial: false}, function() {
        gulp.src(entry).pipe(babel({
            // 不读取外面的babelrc配置,不需要编译成es5
            'babelrc': false,
            'plugins': [
                // ---------------------------------
                ["@babel/plugin-proposal-decorators", {
                    legacy: true
                }],
                // ---------------------------------
                "@babel/plugin-transform-modules-commonjs"
            ]
        }))
        .pipe(gulp.dest('dist'));
    })
}

// 上线环境
function buildProd() {
    return gulp.src(entry).pipe(babel({
        // 不读取外面的babelrc配置,不需要编译成es5
        'babelrc': false,
        'ignore':[configEntry],
        'plugins': [
            // ---------------------------------
            ["@babel/plugin-proposal-decorators", {
                legacy: true
            }],
            // ---------------------------------
            "@babel/plugin-transform-modules-commonjs"
        ]
    }))
    .pipe(gulp.dest('dist'));
}
function buildConfig() {
    return gulp.src(entry)
    .pipe(rollup({
        input: configEntry,
        output: {
            format: 'cjs'
        },
        plugins: [
            replace({
                'process.env.NODE_ENV': JSON.stringify('production')
            })
        ]
    }))
    .pipe(gulp.dest('./dist'))
}
function buildLint() {

}

let build = gulp.series(builddev);

if (process.env.NODE_ENV == 'production') {
    build = gulp.series(buildProd, buildConfig);
}
if (process.env.NODE_ENV == 'lint') {
    build = gulp.series(buildLint);
}
gulp.task('default', build);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

会出现点零了吧碎的小错误,把indexController.js中的关于BaseController的都删了 好,启动成功!