в каждом обратном вызове.
Это плохо. Много программ для 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.