3 способа рендеринга обратного вызова в макет мопса
Есть два способа вернуть значение из асинхронной функции, а именно: обратные вызовы или обещания, но, честно говоря, если вы используете вызов только один раз, это не будет всеэто отличается от встраивания вашего вызова в fs.lstat в вашей маршрутизации, поэтому я предоставлю это в качестве третьего варианта.
Структура каталогов для примера
Если вы хотите следовать здесь,структура каталогов для этого примера.
.
├── app.js
├── stat.js
└── views
└── index.pug
1 directory, 3 files
Установка зависимостей
Вы захотите установить express и pug для этого примера
npm install pug express
Пример макета
Прежде всего, вот пример макета ./views/index.pug
, который мы будем использовать в демонстрационных целях:
html
head
//- This title comes from the express res.render
title= title
body
//- This title comes from the express res.render
h1= title
//- This message comes from the express res.render
p= statResult
Пример 1: обратные вызовы
Это возможная функция создания отчетов о каталогах / файлах с использованиемобратные вызовы. Обратный вызов - это в основном то, что вы уже отправляете в fs.lstat, где просто вносите простое изменение в его вывод, оборачивая его в наш собственный обратный вызов в стиле узла с именем cb
. Обратные вызовы стиля узла обычно имеют два параметра: ошибку в качестве первого параметра и данные в качестве второго. Мы будем следовать шаблону обратного вызова в стиле узла. Обтекание fs.lstat нашим собственным обратным вызовом позволяет функции, вызывающей нашу функцию, получать только те возвращаемые значения, которые мы хотим, а не всю информацию, которую fs.lstat может предоставить в противном случае.
Мы поместили эту функцию в файл с именем stat.js
для примера. Если вы не знаете, что делать с ошибкой внутри stat.js, лучше всего передать ошибку через обратный вызов на тот случай, если вызывающая функция сможет лучше обработать ошибку. Важно не глотать / не терять ошибки в Node.
// stat.js
const fs = require("fs");
module.exports = function (path, cb) {
fs.lstat(path, (err, stats) => {
if (err)
return cb(err);
if (stats.isFile())
return cb(null, `Is file: ${stats.isFile()}`);
if (stats.isDirectory())
return cb(null, `Is directory: ${stats.isDirectory()}`);
});
}
Использование нашей функции обратного вызова
Вот как простое экспресс-приложение будет использовать этот обратный вызов. Мы поместим это в файл сценария с именем app.js
для примера. Обратите внимание, как мы установили для «движка представления» значение «pug», и мы res.render
используем «index.pug» в нашем каталоге представлений.
// app.js
const express = require('express');
const app = express();
const stat = require('./stat.js');
const port = 3020;
app.set('view engine', 'pug');
app.get('/views', function (req, res) {
stat("./views", (err, statResult) => {
if (err) {
res.render("Oops something went wrong!");
console.error(err);
}
res.render('index', {
title: "Views Directory Stat Result",
statResult: statResult
})
})
})
app.get('/', function (req, res) {
stat("./app.js", (err, statResult) => {
if (err) {
res.render("Oops something went wrong!");
console.error(err);
}
res.render('index', {
title: "App.js Stat Result",
statResult: statResult
})
});
})
app.listen(port, function () {
console.log("app listening on http://localhost:" + port)
})
Пример 2: обещания
Обещания - действительно удобный инструмент для асинхронного кода, если вы понимаете их достаточно хорошо, они могут принести огромные улучшения в обработке ошибок.
Вот ваш пример кода статистики с использованием обещания. Обратите внимание, как он возвращает вновь созданное обещание, это важно, потому что обещания - это значения, представляющие значение, которое, скорее всего, наступит в будущем. Конструкторы Promises предоставляют вам функцию разрешения и отклонения. Это связано с тем, что обещание может находиться в любом из трех состояний, «ожидающих», что означает, что оно не завершило свое состояние, не «решено» или «отклонено». Отказ от обещания с ошибкой - это все равно что выдать ошибку в синхронном коде. Это замена для нашего старого stat.js
файла.
// stat.js
const fs = require("fs");
module.exports = function (path) {
return new Promise((resolve, reject) => {
fs.lstat(path, (err, stats) => {
if (err)
return reject(err);
if (stats.isFile())
return resolve(`Is file: ${stats.isFile()}`);
if (stats.isDirectory())
return resolve(`Is directory: ${stats.isDirectory()}`);
});
})
}
Ниже описано, как использовать этот файл stat.js
в простом приложении. Стоит отметить, что вы должны объединить .then
s в обещании получить значение из них, если они разрешены, и если вы хотите поймать любое отклоненное обещание, вам нужно использовать .catch
, чтобы поймать их. Как и в случае с кодом синхронизации, когда вы улавливаете ошибку, она предполагает, что вы обработали ошибку, если не сбросили ее. Есть много вещей, которые нужно знать об обещаниях, и я не буду охватывать все ради краткости, но я приведу ссылки на некоторые статьи внизу, где вы можете узнать больше.
Хотя альтернативой цепочке являетсяиспользуйте async / await, где вы используете функцию с ключевым словом async
перед ключевым словом функции, которое позволяет вам использовать await
значение Promise, как если бы оно было синхронным. Вы можете думать, что await
разворачивает ценность обещания. Ниже приведен код для нового app.js
в реализации обещания, с маршрутом /views
, выполняющим связывание API, и маршрутом /
, выполняющим async / await api:
// app.js
const express = require('express');
const app = express();
const stat = require('./stat2.js');
const port = 3020;
app.set('view engine', 'pug');
app.get('/views', function (req, res) {
stat("./views").then(statResult => {
res.render('index', {
title: "Views Directory Stat Result",
statResult: statResult
})
}).catch(function (err) {
res.render("Oops something went wrong!");
console.error(err);
})
})
app.get('/', async function (req, res) {
try {
const statResult = await stat("./app.js");
res.render('index', {
title: "App.js Stat Result",
statResult: statResult
})
} catch (err) {
res.render("Oops something went wrong!");
console.error(err);
}
})
app.listen(port, function () {
console.log("app listening on http://localhost:" + port)
})
Пример 3: ВстраиваниеПозвоните в lstat
Это, вероятно, не то, что вы хотите сделать, если вы не хотите повторяться, но всегда есть возможность встроить ваш вызов в lstat. Таким образом, вы бы толькоу меня есть файл app.js
, и он будет выглядеть так:
// app.js
const express = require('express');
const app = express();
const fs = require('fs');
const port = 3020;
app.set('view engine', 'pug');
app.get('/views', function (req, res) {
fs.lstat("./views", (err, stats) => {
if (err) {
res.render("Oops something went wrong!");
console.error(err);
}
let statResult = "";
if (stats.isFile())
statResult = `Is file: ${stats.isFile()}`;
if (stats.isDirectory())
statResult = `Is directory: ${stats.isDirectory()}`;
res.render('index', {
title: "Views Directory Stat Result",
statResult: statResult
})
});
})
app.get('/', function (req, res) {
fs.lstat("./app.js", (err, stats) => {
if (err) {
res.render("Oops something went wrong!");
console.error(err);
}
let statResult = "";
if (stats.isFile())
statResult = `Is file: ${stats.isFile()}`;
if (stats.isDirectory())
statResult = `Is directory: ${stats.isDirectory()}`;
res.render('index', {
title: "App.js Stat Result",
statResult: statResult
})
});
})
app.listen(port, function () {
console.log("app listening on http://localhost:" + port)
})
Ну, это всего лишь три способа вернуть асинхронное значение, которое будет отображаться в pug. Надеюсь, что это поможет, не стесняйтесь задавать мне любые ваши вопросы об этом коде в комментариях. Я искренне предлагаю получить хорошие обещания для вещей, которые при вызове имеют только одно возвращаемое значение.
Вот несколько ссылок на обещания:
Использование обещаний MDN
JavaScript-обещания Джейка Арчибальда: введение