专栏首页IMWeb前端团队Unix Pipes to Javascript Pipes

Unix Pipes to Javascript Pipes

本文作者:IMWeb 杨文坚 原文出处:IMWeb社区 未经同意,禁止转载

Unix Pipes

Unix管道扫描稿

简单样例:

$ netstat -apn | grep 8080

相信这个大家经常使用,这里就不细说了。

那么管道基本思想是什么呢?

  • 让每个程序只完成一件事,并将其做好(do one thing and do it well),完成一个新任务,新建一个程序,而不是在旧程序中添加新特性
  • 标准化每个程序的输入和输出,让任意符合标准的程序可以串在一起(write programs to work together)
  • 设计和创造软件,而不是架构或系统

NodeJS Stream

NodeJS中引入流概念来解决I/O异步问题,如果没有Stream,我们可能要这么写代码:

var http = require('http');
var fs = require('fs');

// 著名的回调地狱又来了
var server = http.createServer(function (req, res) {
    fs.readFile(__dirname + '/data.txt', function (err, data) {
        res.end(data);
    });
});
server.listen(8000);

但有了Stream,我们就可以更优雅的编写代码:

var http = require('http');
var fs = require('fs');

var server = http.createServer(function (req, res) {
    var stream = fs.createReadStream(__dirname + '/data.txt');
    // 把两个管子接起来
    stream.pipe(res);
});
server.listen(8000);

想添加一个新功能?要用gzip压缩文件?OK,可以这么写:

var http = require('http');
var fs = require('fs');
var oppressor = require('oppressor');

var server = http.createServer(function (req, res) {
    var stream = fs.createReadStream(__dirname + '/data.txt');
    // 将三个管子连起来
    stream.pipe(oppressor(req)).pipe(res);
});
server.listen(8000);

Back-end to Font-end

随着EventStream、Gulp、Webpack管道在后端的盛行,管道逐渐从后端向前端渗透,如Angular、Vuejs。我们在Q.js、高可扩展数据层组件DB.core中大量使用了管道过滤器(Pipe-And-Filter)模式。

(webpack的核心:管道式插件)

那么前端的管道又是怎样的呢?让我们看看DB.core中的例子。

Pipes in DB.core

DB的设计初衷在于解决CGI拉取的通用性问题,例如:区分正确和错误逻辑、通用错误逻辑处理、登陆态通用处理。但DB却难以复用,因为我们发现每个业务的通用性各不相同,通常我们新起一个业务总是要将DB复制下来后做大量侵入式修改,才能适用于新的业务要求。而在齐齐互动视频中,我们例如管道过滤器模式重构了我们的DB。 具体请参见:https://github.com/miniflycn/db

问题在哪里?

  • Rule of Simplicity: Design for simplicity; add complexity only where you must.
  • Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do.

DB干了太多事情,导致每次干一件事情就要插入各种代码。通过管道过滤器模式,将每件事情拆成独立的过滤器,每个过滤器只做一件事,但将一件事情做到极致。

单一功能原则(Single responsibility principle)规定每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。所有它的(这个类的)服务都应该严密的和该功能平行(功能平行,意味着没有依赖)。 马丁把功能(职责)定义为:“改变的原因”,并且总结出一个类或者模块应该有且只有一个改变的原因。一个具体的例子就是,想象有一个用于编辑和打印报表的模块。这样的一个模块存在两个改变的原因。第一,报表的内容可以改变(编辑)。第二,报表的格式可以改变(打印)。这两方面会的改变因为完全不同的起因而发生:一个是本质的修改,一个是表面的修改。单一功能原则认为这两方面的问题事实上是两个分离的功能,因此他们应该分离在不同的类或者模块里。把有不同的改变原因的事物耦合在一起的设计是糟糕的。 ——from wiki

前端常用的管道过滤器模式基本实现
    /**
     * _apply
     * @param {Array} handles 处理函数列队,每一个是一个管子
     * @param {*} data 要处理的数据
     * @param {Object} options 可选参数
     * @param {Function} cb 处理后回调
     */
    _apply: function (handles, data, options, cb) {
        var i = 0,
            l = handles.length,
            res = data;
        for (i; i < l; i++) {
            res = handles[i].call(this, res, options);
            // if handle return false, just break
            if (res === false) return;
        }
        cb(res);
    },
db.core完整实现
var $ = require('jquery');

/**
 * DB
 * @class
 * @param {Object} options this is just a $.ajax setting
 *      @param {Array} options.errHandles
 *      @param {Array} options.succHandles
 *      @param {Function} options.succ
 *      @param {Function} options.err
 */
function DB(options) {
    this._init(options);
}
$.extend(DB.prototype, {
    _init: function (options) {
        this.errHandles = options.errHandles || [];
        this.succHandles = options.succHandles || [];
        this.errHandles.unshift.apply(this.errHandles, DB.options.errHandles || []);
        this.succHandles.unshift.apply(this.succHandles, DB.options.succHandles || []);
        options = $.extend({}, DB.options || {}, options);
        this.options = options;
    },
    _wrap: function (options) {
        var self = this;
        options.success = function (data) {
            // you may want to modify this line for judging error or success
            data.retcode === 0 ?
                self._apply(self.succHandles, data, options, options.succ) :
                self._apply(self.errHandles, data, options, options.err);
        };
        options.error = function (data) {
            self._apply(self.errHandles, data, options, options.err);
        };
        return options;
    },
    _apply: function (handles, data, options, cb) {
        var i = 0,
            l = handles.length,
            res = data;
        for (i; i < l; i++) {
            res = handles[i].call(this, res, options);
            // if handle return false, just break
            if (res === false) return;
        }
        cb(res);
    },
    /**
     * ajax
     * @param {Object} options this is just a $.ajax setting
     *      @param {Function} options.succ
     *      @param {Function} options.err
     */
    ajax: function (options) {
        options = this._wrap($.extend({}, this.options, options));
        !options.data &&
            (options.data = options.param);
        $.ajax(options);
    }
});
$.extend(DB, {
    httpMethod: function (options) {
        var db = new DB(options);
        return function (opt) {
            db.ajax(opt);
            return this;
        };
    },
    extend: jQuery.extend,
    // default options
    options: {}
});

module.exports = DB;

这样我们就可以把以前的各种业务数据检测,甚至是数据组装都放在succHandles和errHandles进行。这是我们在齐齐项目中使用的一个例子,可以看见,我们把数据组装也放在了DB层进行。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Unix Pipes to Javascript Pipes

    本文作者:IMWeb 杨文坚 原文出处:IMWeb社区 未经同意,禁止转载 Unix Pipes Unix管道扫描稿 ? 简单样例: $ ne...

    IMWeb前端团队
  • 作为一个前端,可以如何机智地弄坏一台电脑?

    无论你触发了多少bug,最多导致浏览器崩溃,对系统影响不到哪去。 这就像二次元各种炫酷的毁灭世界,都不会导致三次元的世界末日。 然而,作为一个前端,我发现是有方...

    IMWeb前端团队
  • 作为一个前端,可以如何机智地弄坏一台电脑?

    有人说,前端的界限就在浏览器那儿。 无论你触发了多少bug,最多导致浏览器崩溃,对系统影响不到哪去。 这就像二次元各种炫酷的毁灭世界,都不会导致三次元的世界末日...

    IMWeb前端团队
  • Unix Pipes to Javascript Pipes

    本文作者:IMWeb 杨文坚 原文出处:IMWeb社区 未经同意,禁止转载 Unix Pipes Unix管道扫描稿 ? 简单样例: $ ne...

    IMWeb前端团队
  • pytorch学习笔记(八):PytTorch可视化工具 visdom

    Visdom PyTorch可视化工具 本文翻译的时候把 略去了 Torch部分。 项目地址 ? 一个灵活的可视化工具,可用来对于 实时,富数据的 创建,组织和...

    ke1th
  • 【带着canvas去流浪】 (3)绘制饼图

    使用原生canvasAPI绘制饼图(南丁格尔玫瑰)。(截图以及数据来自于百度Echarts官方示例库【查看示例链接】)。

    大史不说话
  • asp dotnet core 3.0 接口返回 json 使用 PascalCase 格式

    在 asp dotnet core 3.0 默认的 webapi 返回接口都是返回 json 格式,同时这个 json 格式使用的是 CamelCase 属性名...

    林德熙
  • Spring Boot 之Servlet、Listener、Filter

    wuweixiang
  • Java 实现 markdown转Image

    markdown 转 image 前段时间实现了长图文生成的基本功能,然后想了下能否有个进阶版,直接将markdown生成渲染后的图片呢? 思路 有不少的库...

    一灰灰blog
  • 自己动手写Web服务器(一)简单的静态服务器

    前几天开始看《How Tomcat Works》,因为有人推荐要研究tomcat源代码,看这本书是很有帮助的。

    the5fire

扫码关注云+社区

领取腾讯云代金券