zoukankan      html  css  js  c++  java
  • Unix Pipes to Javascript Pipes

    Unix Pipes

    Unix管道扫描稿

    1

    简单样例:

    $ 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)模式。

    2

    (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层进行。

    1

  • 相关阅读:
    CSUFT 1002 Robot Navigation
    CSUFT 1003 All Your Base
    Uva 1599 最佳路径
    Uva 10129 单词
    欧拉回路
    Uva 10305 给任务排序
    uva 816 Abbott的复仇
    Uva 1103 古代象形文字
    Uva 10118 免费糖果
    Uva 725 除法
  • 原文地址:https://www.cnblogs.com/justany/p/4397236.html
Copyright © 2011-2022 走看看