12Sep

node_js_by_myvushka-d8yrtqh
Несколько особняком в Node.js стоит наследование отстроенного объекта ошибки Error. На этом примере я объясню сначала, зачем оно может понадобиться, а потом – как его делать правильно.

// Inheritance from Error  
  
var util = require('util');  
  
var phrases = {  
  "Hello": "Hello",  
  "world": "World"  
};  
  
  
function getPhrase(name) {  
  if (!phrases[name]) {  
    throw new Error("There is no such a pharase: " + name);  
  }  
  return phrases[name];  
}  
  
  
function makePage(url) {  
  
  if (url != 'index.html') {  
    throw new Error("There is no such a pharase");  
  }  
  
  return util.format("%s, %s!", getPhrase("Hello"), getPhrase("world"));  
}  
  
  
var page = makePage('index.html');  
console.log(page);  

Здесь код состоит из двух функций. Первая – getPhrase.

function getPhrase(name) {
    if (!phrases[name]) {
        throw new Error("There is no such a phrase: " + name);
    }
    return phrases[name];
}

Это самая простейшая функция по интернационализации, которая только может быть. Она берет название фразы (name) и возвращает соответствующие данные, если они есть, а если нет – то исключение (“There is no such a phrase”).

Вторая функция – makePage:

function makePage(url) {  
  
  if (url != 'index.html') {  
    throw new Error("There is no such a page");  
  }  
  
  return util.format("%s, %s!", getPhrase("Hello"), getPhrase("world"));  
}  

Эта функция получает url. Сейчас она умеет работать только с index.html. Поэтому, для остальных она выдает ошибку, а если это index.html, то возвращает его отформатированную строку. Давайте посмотрим, как работает вот такой код:

var page = makePage('index.html');  
console.log(page); 

Запускаем. Работает. «Hello World» вывел отформатированную строку. Все верно. А теперь давайте добавим к этому коду правильную обработку ошибок. Например, если мы получили некорректный url, несуществующий, тогда makePage бросит ошибку «Нет такой страницы», и если представить себе, что это веб сервер, то это означает, что мы должны вывести пользователю сообщение: 404 – страница не найдена. Это один вариант ошибки, одна обработка. А посмотрим, что будет, если неизвестна фраза. Если в каком-то месте кода мы вызвали получение фразы, например, вот так:

return util.format("%s, %s!", getPhrase("Hell"), getPhrase("world"));

То «Нет такой фразы» – это уже другая ошибка. И тогда нужно уже не 404 сделать, а статус 500 и обязательно написать уведомление системному администратору, что что-то тут не так, словарь не полон, его срочно нужно поправить. Это программная ошибка, поэтому обрабатывать ее нужно по-другому.

К сожалению, в текущем коде

var page = makePage('index.html');  
console.log(page); 

даже если я добавлю try catch вокруг функции makePage, все равно понять где какая ошибка нельзя. И то, и другое это просто ошибки класса error. С точки зрения объектно ориентированного программирования разумным способом решения этой проблемы будет  сделать свои объекты ошибки для разных случаев. Здесь это будет

function getPhrase(name) {  
  if (!phrases[name]) {  
    throw new PhraseError("There is no such a phrase: " + name);  
  }  
  return phrases[name];  
} 

А здесь

function makePage(url) {  
  
  if (url != 'index.html') {  
    throw new HttpError(404, "There is no such a page");  
  } 

И в его конструкторе мы заодно указали статус – 404. Соответственно, для тех ошибок, которые мы должны показать пользователю вида Http мы будем использовать вот эти ошибки: HttpError, а для ошибок, связанных с переводом – PhraseError(“Нет такой фразы: ” + name).

Объявим соответствующие классы при помощи util inherits. Например, вот так:

function PhraseError(message) {  
  this.message = message;  
}  
util.inherits(PhraseError, Error);  
PhraseError.prototype.name = 'PhraseError';  

И вот так:

function HttpError(status, message) {  
  this.status = status;  
  this.message = message;  
}  
util.inherits(HttpError, Error);  
HttpError.prototype.name = 'HttpError';  

Сразу же посмотрим на особенности работы с объектом ошибок. Какие свойства нам здесь нужны? Первое, конечно же, message. Для того, чтобы поставить  message, мне нужно сделать это вручную. Это есть такая особенность работы с ошибками. То есть, не вызов стандартного родителя суперкласса, то есть, Error.apply(this, arguments): – вот так мы обычно вызываем конструктор суперкласса. В данном случае, ничего он полезного нам не сделает. Необходимо поставить вручную.

Следующее свойство, которое есть у всех встроенных ошибок, это name. По этому свойству мы можем абсолютно точно понять, что за ошибка у нас есть. Оно у всех встроенных ошибках в прототипах есть, поэтому и сюда тоже мы запишем.

Наконец, последнее свойство, которое нам будет важно, это stack. О нем чуть позже.

Итак, давайте сейчас запущу код

var util = require('util');
var phrases = {
    "Hello": "Hello",
    "world": "World"
};

// message name stack
function PhraseError(message) {
    this.message = message;
}
util.inherits(PhraseError, Error);
PhraseError.prototype.name = 'PhraseError';


function HttpError(status, message) {
    this.status = status;
    this.message = message;
}
util.inherits(HttpError, Error);
HttpError.prototype.name = 'HttpError';


function getPhrase(name) {
    if (!phrases[name]) {
        throw new PhraseError("There is no such a phrase: " + name);
    }
    return phrases[name];
}

function makePage(url) {
    if (url != 'index.html') {
        throw new HttpError(404, "There is no such a page");
    }
    return util.format("%s, %s!", getPhrase("*****"), getPhrase("world"));
}

try {
    var page = makePage('index');
    console.log(page);
} catch (e) {
    if (e instanceof HttpError) {
        console.log(e.status, e.message);
    } else {
        console.error("Error %s\n message: %s\n stack: %s", e.name, e.message, e.stack);
    }
}

Как видим, тут makePage(“index”); – это неизвестный url, поэтому мы должны получить ошибку HttpError.  Такую ошибку мы обрабатываем вот так:

 console.log(e.status, e.message);

Просто выводим без всякой паники. Запускаем:

node errors

Все работает.

Теперь посмотрим на другой вариант, а именно, если url правильный (обратите внимание что жирным в коде ниже выделены измененные строчки), но ошибка произошла в программе, то есть, высветилась какая-то непонятная фраза, которой точно нету. В данном случае, если ошибка какая-то другая, мы должны на нее отреагировать совсем иначе. Паника, кошмар, программная ошибка! Срочно всех поднимаем и исправляем! Эта ветка кода будет действовать для все программных ошибок, в том числе и для встроенных, а не только для PhraseError

function makePage(url) {  
  if (url != 'index.html') {  
    throw new HttpError(404, "Нет такой страницы");  
  }  
  return util.format("%s, %s!", getPhrase("

*****

"), getPhrase("world"));  
}  
  
try {  
  var page = makePage('

index.html

');  
  console.log(page);  
} catch (e) {  
  if (e instanceof HttpError) {  
    console.log(e.status, e.message);  
  } else {  
    console.error("Ошибка %s\n сообщение: %s\n стек: %s", e.name, e.message, e.stack);  
  }  
}  

Запускаем. Вывел, действительно, console.error. Посмотрим на свойства. Все правильно. А вот свойство stack должно хранить информацию о том, где, в каком файле произошла эта ошибка, что ей предшествовало. В конструкторах я не произвел никаких специальных действий, которые правильно поставят stack. И в стандартных java script их вообще не предусмотрено. Я просто создаю новый объект. На самом деле, есть разные круги, которые позволяют получить stack, но здесь они нам не понадобятся, поскольку в V8 есть специальная JS команда, которая не входит в стандарт, но позволяет получить stack. Выглядит она так:

function PhraseError(message) {
    this.message = message;
    Error.captureStackTrace(this);
}

Эта команда получает текущий stack, то есть, последовательность сложенных вызовов, которые при текущем месте кода, и сохраняют его в  this, то есть, в объекте ошибки. Давайте посмотри, что у нас получится сейчас. Вот теперь оно вывело stack, то есть, то место, где это все и произошло. Но если посмотреть внимательно ошибка произошла, на самом деле, вот здесь:

throw new PhraseError("There is no such a pharase: " + name);

Нас интересует, то, что произошло тут, и как к этому мы дошли. То, что происходило внутри PhraseError, нас, в принципе, не интересует. Эта строчка stack в данному случае лишняя. Чтобы ее убрать, в captureStackTrace предусмотрен второй необязательный специальный параметр. Это функция, до которой будет собираться StackTrace. То есть, если здесь я укажу текущий конструктор

Т.е. в функции HttpError

Error.captureStackTrace(this, HttpError);

и в функции PhraseError

Error.captureStackTrace(this, PhraseError);

сделаю следующие изменения.

То, при этом, тот stack,  который внутри этой функции, не будет здесь показан, не будет собран. Давайте проверим. Я перезапустил, и лишняя строка теперь вырезана.

Итак, мы получили унаследованные объекты ошибки с правильными свойствами message, name и с возможностью вывести stack.

Код урока вы можете скачать здесь

ogimage

Материалы для урока взяты из следующего скринкаста.

We are looking forward to meeting you on our website soshace.com

Уроки Express.js . Логгер, Конфигурация, Шаблонизация с EJS. Часть 2.

Favicon – это все connect Middleware, он смотрит, если url имеет вид favicon.ico, то он читает favicon и выдает, а иначе передает управления дальше. Логгер выводит запись о том, что у нас за запрос пришел. Например, если сейчас запустить приложение, то логгер что-то выведет, если мы зайдем на:

Уроки React. Урок 12.

Всем привет! Сейчас мы пробежимся по нашему домашнему заданию, а также дадим важные комментарии , которые помогут Вам в дальнейшей работе с React. Для удобства Вам понабиться видеть перед собой код, поэтому перейдите на нужный commit и мы продолжим. Начнем с connect.connect нужен нам, чтобы обратиться к store. Добавим небольшую ремарку, что если Вы можете передать данные используя обычные props – передавайте. Например в containers/Articles.js мы обращаемся к store чтобы из его state достать необходимые нам статьи: