Переосмысление книги Эдди Османи «Паттерны для масштабируемых JavaScript-приложений»

Материал из support.qbpro.ru
Версия для печати больше не поддерживается и может содержать ошибки обработки. Обновите закладки браузера и используйте вместо этого функцию печати браузера по умолчанию.

Андрей Климов.


Спасибо команде переводчиков за их огромный труд. Сам перевод находится здесь

Итак, скорее всего будет не профессионально, но как есть. (А то сам забудешь и другие не вспомнят)

В главе 9 предложен клевый шаблон проектирования - фасад. Вот его скелет


var module = (function() {
  var _private = {
    i: 5,
    get: function() {
      console.log('Текущее значение:' + this.i);
    },
    set: function(val) {
      this.i = val;
    },
    run: function() {
      console.log('процесс запущен');
    },
    jump: function() {
      console.log('резкое изменение');
    }
  };
  return {
    facade: function(args) {
      _private.set(args.val);
      _private.get();
      if (args.run) {
        _private.run();
      }
    }
  }
}());

module.facade({run:true, val:10}); // Текущее значение: 10, процесс запущен

Попробуем его применить к практике. Напишу асинхронный модуль, который возвращает список всех файлов в директории и всех вложенных поддиректориях определенным расширением (.html).

Фасад для асинхронного рекурсивного чтения списка фалов в директории

Проверено nodejs 0.11.12 Debian wheezy x86_64

#!/usr/bin/env node

"use strict";
var fs = require('fs');
var path = require('path');
var util = require('util');


var this_module = (function () {
    var _private = {
        "__dirname": "/home/html_path",
        "__extention": /\.html$/i,
        "debug": false,
        "result": [],
        "reader": function (_dirname, extension, callback) {
            var results = [];
            var that = this;
            fs.readdir(_dirname, function (err, list) {
                if (err) return callback(err);
                var pending = list.length;
                if (!pending) return callback(null, results);
                list.forEach(function (file) {
                    file = _dirname + '/' + file;

                    fs.stat(file, function (err, stat) {
                        if (stat && stat.isDirectory()) {
                            that.reader(file, extension, function (err, res) {
                                results = results.concat(res);
                                if (!--pending) callback(null, results);
                            });
                        } else {
                            /*выбираем файлы которые соответствуют рег выражению*/
                            /*если убрать это условие в массив попадут все файлы*/


                            if (extension.test(file)) {
                                results.push(file);
                            }
                            if (!--pending) callback(null, results);
                        }
                    });
                });
            });
        },
        "cbk": function (err, result) {
            if (err) {
                console.error(util.inspect(err));
                return;
            }
            console.log(util.inspect(result));
            return result;
        },
        "read": function (dir, ext) {
            ext = ext || this.__extention;
            dir = dir || this.__dirname;
            this.reader(dir, ext, this.cbk);
        }
    };
    return {
        read_file_list: function (args) {
            _private.read();
        }
    }
}());

this_module.read_file_list()

Замыкание остается в памяти до прекращения процесса. А если это не нужно. Например при запуске кода в виртуальной машине Nodejs. Переделаем фасад для этой цели.

#!/usr/bin/env node

"use strict";
var fs = require('fs');
var path = require('path');
var util = require('util');


var this_module = {
    _private: {
        "__dirname": "/home/html_path",
        "__extention": /\.html$/i,
        "debug": false,
        "result": [],

        "reader": function (_dirname, extension, callback) {
            var results = [];
            var that = this;
            /*============================*/
            fs.readdir(_dirname, function (err, list) {
                if (err) return callback(err);
                var pending = list.length;
                if (!pending) return callback(null, results);
                list.forEach(function (file) {
                    file = _dirname + '/' + file;

                    fs.stat(file, function (err, stat) {
                        if (stat && stat.isDirectory()) {
                            that.reader(file, extension, function (err, res) {
                                results = results.concat(res);
                                if (!--pending) callback(null, results);
                            });
                        } else {
                            /*выбираем файлы которые соответствуют рег выражению*/
                            /*если убрать это условие в массив попадут все файлы*/


                            if (extension.test(file)) {
                                results.push(file);
                            }
                            if (!--pending) callback(null, results);
                        }
                    });
                });
            });
            /*============================*/
        },
        "cbk": function (err, result) {
            if (err) {
                console.error(util.inspect(err));
                return;
            }
            console.log(util.inspect(result));
            return result;
        },
        "read": function (dir, ext) {
            ext = ext || this.__extention;
            dir = dir || this.__dirname;
            this.reader(dir, ext, this.cbk);
        }
    }
};

function ret() {
    return this._private.read();
}

var bound = ret.bind(this_module);
exports.reader = bound;


Пример использования

#!/usr/bin/env node

"use strict";
var util = require('util');
var file_list_reader = require('./mod_async_file_list3').reader;
var file_list = file_list_reader();
console.log(file_list);