Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

README.md

Описание

Цель работы: научиться оборачивать интерфейсы и добиться такой универсальности обертки, чтобы не зависеть от того, какой именно интерфейс она оборачивает. В качестве примера обернута одна функция setTimeout, а в качестве задания мы обернем целый интерфейс работы с файловой системой - библиотеку fs.

Файлы

  • framework.js - кусочек фреймворка, демонстрирующий обертку (wrapper)
  • application.js - часть приложения для демонстрации обертки

Запуск

Из командной строки пишем node application, а потом node framework, сравниваем вывод, смотрим код framework.js и application.js, понимаем как работает обертка вокруг setTimeout

Задание

  1. Нужно изучить, как обернут таймер. По аналогии с оберткой таймера нужно сделать обертку вокруг модуля fs. Все его функции нужно пройти в цикле for (const key in fs) { ... } и заменить на свою функцию. При помощи замыкания эта функция должна стать универсальной прослойкой для всех функций библиотеки fs. Смысл обертки - логировать все вызовы к файловой системе в файл, с указанием времени, имени функции, ее аргументов, а если функция имеет еще и callback, то нужно перехватывать и его, тоже логируя в файл момент, вызова callback. Это задание можно разбить на несколько шагов.
  2. Удаляем из application.js вызов таймера и оставляем там только код:
const fileName = './README.md';
console.log('Application going to read ' + fileName);
fs.readFile(fileName, (err, src) => {
  console.log('File ' + fileName + ' size ' + src.length);
});

Это пример работы с файлом. И мы будем изменять поведение этого кода. Убираем из framework.js обертку таймера и пробрасываем fs в приложение. Теперь запускаем node framework и убеждаемся, что файл считывается и выводится его длина. 3. Теперь пишем функцию cloneInterface(interfaceName) для копирования всех ключей из библиотеки fs в новый интерфейс и передаем в песочницу не исходный fs, а склонированный. Пример функции клонирования:

const cloneInterface = (anInterface) => {
  const clone = {};
  for (const key in anInterface) {
    clone[key] = anInterface[key];
  }
  return clone;
};
  1. Пишем функцию wrapFunction(fnName, fn) которая оборачивает функцию fn и возвращает функцию-замыкание от wrapper. Замыкание, это ссылка на копию функции wrapper, которая замкнута на контекст wrapFunction. Таким образом мы применяем функциональное наследование и порождаем такой вариант wrapper, который видит параметры fnName и 'fn' от wrapFunction. Мы полностью передаем все аргументы в функцию fn:
const wrapFunction = (fnName, fn) => (...args) => {
  console.log('Call: ' + fnName);
  console.dir(args);
  return fn(...args);
}
  1. Определяем, есть ли среди аргументов callback, он всегда последний в массиве аргументов и его тип function. Если callback есть, то вместо него передаем свою функцию, которая логирует все аргументы и вызывает настоящий callback.
  2. Теперь можно из application.js использовать другие функции fs и убедиться, что все они обернуты.
  3. Добавляем таймеры в application.js и на таймерах работаем с файлами, а из framework.js собираем статистику работы с файлами и выводим ее каждые 30 секунд. Например, можно собирать несколько из этих параметров
  • количество обращений к функциям,
  • количество колбэков,
  • среднюю скорость завершения функций,
  • среднюю скорость возвращения колбеков,
  • общий объем прочитанных с диска данных,
  • общий объем записанных данных,
  • среднюю скорость чтения и записи, и т.д.

Сохраните наработки этой лабораторной работы, они понадобятся для выполнения следующих работ, в частности, работы по передаче вызовов в другой процесс и другой сервер. Это позволит распределить исполнение приложения.

Дополнительные задания

  1. Попробуйте подставить в качестве файловой системы свою структуру из памяти, и прочитать из нее при помощи fs.readFile, потом записать файл, создать и удалить. Пример структуры:
const virtualFs = {
  folder: {
    subfolder: {
      file1: 'File content',
      file2: 'Another file content'
    },
  },
  notes: {
    myToDos: 'Refactor projects, Prepare tests',
    meetings: 'Meet thoughts at 10:00 walking along garden'
  }
};
  1. Реализуйте кеширование файловых операций в памяти.
  2. Напишите аналогичный пример на другом языке программирования.