Выразительный JavaScript (Хавербеке) - страница 225

в каждом обратном вызове.

Это плохо. Много программ для Node написаны так, чтобы использовать как можно меньше работы с исключениями, подразумевая что в случае возникновения исключения программа не может его обработать, и поэтому надо падать.

Ещё один подход – использование обещаний, которые были описаны в главе 17. Они ловят исключения, выброшенные функциями обратного вызова и передают их как ошибки. В Node можно загрузить библиотеку >promise и использовать её для обработки асинхронных вызовов. Немногие библиотеки Node интегрируют обещания, но обычно их довольно просто обернуть. Отличный модуль >“promise” с NPM содержит функцию >denodeify, которая берёт асинхронную функцию вроде >fs.readFile и преобразовывает её в функцию, возвращающую обещание.

>var Promise = require("promise");

>var fs = require("fs");


>var readFile = Promise.denodeify(fs.readFile);

>readFile("file.txt", "utf8").then(function(content) {

>  console.log("The file contained: " + content);

>}, function(error) {

>  console.log("Failed to read file: " + error);

>});

Для сравнения, я написал ещё одну версию файлового сервера с использованием обещаний, которую можно найти на eloquentjavascript.net/code/file_server_promises.js. Она почище, потому что функции теперь могут возвращать результаты, а не назначать обратные вызовы, и исключения передаются неявно.

Приведу несколько строк оттуда, чтобы продемонстрировать разницу в стилях.

Объект >fsp, использующийся в коде, содержит варианты функций >fs с обещаниями, обёрнутыми при помощи >Promise.denodeify. Возвращаемый из обработчика метода объект, со свойствами >code и >body, становится окончательным результатом цепочки обещаний, и он используется для определения того, какой ответ отправить клиенту.

>methods.GET = function(path) {

>  return inspectPath(path).then(function(stats) {

>    if (!stats) // Does not exist

>      return {code: 404, body: "File not found"};

>    else if (stats.isDirectory())

>      return fsp.readdir(path).then(function(files) {

>        return {code: 200, body: files.join("\n")};

>      });

>    else

>      return {code: 200,

>              type: require("mime").lookup(path),

>              body: fs.createReadStream(path)};

>  });

>};


>function inspectPath(path) {

>  return fsp.stat(path).then(null, function(error) {

>    if (error.code == "ENOENT") return null;

>    else throw error;

>  });

>}

Функция >inspectPath – простая обёртка вокруг >fs.stat, обрабатывающая случай, когда файл не найден. В этом случае мы заменяем ошибку на успех, возвращающий >null. Все остальные ошибки можно передавать. Когда обещание, возвращаемое из этих обработчиков, обламывается, сервер отвечает кодом 500.