如何在 Node.js 和 Express.js 中改进此代码以避免回调地狱
How to improve this code in Node.js and Express.js avoiding callback hell
我的一个控制器中有一个方法。控制器的目的是使用 webshot package.
打印一组 url
这是有问题的代码:
router.post('/capture', function (req, res, next) {
//Check params remove
var json = JSON.parse(req.body.data);
var promise = new Promise(function (resolve, reject) {
var totalImages = Object.keys(json).length;
var arrayListUrlImages = new Array(totalImages);
var counter = 0;
var completeDir = dir + ''; //Directory URL
for (var value of json) {
var url = 'http://example.com/' + id + '/' + value.anotherValue;
var folder = completeDir + id + '/' + value.anotherValue + '.jpg';
//Options for capturing image
var options = {
renderDelay: 1000,
quality: 100,
phantomConfig:
{
'local-to-remote-url-access': 'true',
'ignore-ssl-errors': 'true'
}
};
var anotherValue = value.anotherValue;
(function (anotherValue) {
webshot(url, folder, options, function (err) {
// screenshot now saved
if (err === null) {
var urlImage = "http://example.com/images/" + id + "/" + anotherValue + ".jpg";
arrayListUrlImages.push(urlImage);
counter++;
console.log("Counter: " + counter);
if (counter === totalImages) {
resolve(arrayListUrlImages);
}
}
else {
reject(err);
}
});
})(anotherValue);
}
}).then(function (arrayImages) {
res.send(arrayImages);
}).catch(function (errorVale) {
res.send(null);
});
});
这段代码没有问题...但我想做得更好。我不知道有多少 URL 需要检查(这是重要的细节,因为我需要为每个或类似的 做一个检查)。
我读过关于 async package... 是否更好的选择是将此代码移动到类似 async.parallel 的位置?我可以在我的代码中使用 yield 吗?
谢谢!
既然你用的是Promise,我推荐Promise.all。
It returns a promise that resolves when all of the promises in the iterable argument have resolved, or rejects with the reason of the first passed promise that rejects.
看来它解决了你的问题。
示例:
downloadOne = url => new Promise(resolve => {
webshot(url, ....., (err, res) => resolve(res));
})
router.post('/capture', function (req, res, next) {
var urls = JSON.parse(req.body.data);
Promise.all(urls.map(downloadOne)).then(req.send);
}
老实说,您的代码看起来不错。
如果您不打算在此处添加更多逻辑,请保持原样。
可以做得更好的是将其迁移到 ES6 语法并提取另一个值函数,但我不知道这是否适用于您的情况。
对于这样简单的示例,您不需要使用 async
。使用原生承诺:
router.post('/capture', function (req, res, next) {
//Check params remove
const json = JSON.parse(req.body.data);
Promise.all(Object.getOwnPropertyNames(json).map((key) => {
var value = json[key];
var url = 'http://example.com/' + id + '/' + value.anotherValue;
var folder = completeDir + id + '/' + value.anotherValue + '.jpg';
//Options for capturing image
var options = {
renderDelay: 1000,
quality: 100,
phantomConfig:
{
'local-to-remote-url-access': 'true',
'ignore-ssl-errors': 'true'
}
};
return new Promise((resolve, reject) => {
webshot(url, folder, options, function (err) {
if (err) {
reject(err);
return;
}
var urlImage = "http://example.com/images/" + id + "/" + anotherValue + ".jpg";
resolve(urlImage);
}
});
}))
.then((listOfUrls) => {
res.json(listOfUrls); // List of URLs
}, (error) => {
console.error(error);
res.json(null);
});
});
这是一个基于内部函数的代码流示例:
router.post('/capture', function (req, res, next) {
// Definitions
// Load image
function loadImage(value) {
var url = 'http://example.com/' + id + '/' + value.anotherValue;
var folder = completeDir + id + '/' + value.anotherValue + '.jpg';
//Options for capturing image
var options = {
renderDelay: 1000,
quality: 100,
phantomConfig:
{
'local-to-remote-url-access': 'true',
'ignore-ssl-errors': 'true'
}
};
return webshotPromise(url, folder, options);
}
// Load whebshot as a promise
function webshotPromise(url, folder, options) {
return new Promise((resolve, reject) => {
webshot(url, folder, options, function (err) {
if (err) {
reject(err);
}
var urlImage = "http://example.com/images/" + id + "/" + anotherValue + ".jpg";
resolve(urlImage);
}
});
}
// The method flow
const json = JSON.parse(req.body.data);
// Get json keys and iterate over it to load
Promise.all(
Object.getOwnPropertyNames(json).map(key => loadImage(json[key]))
)
// Got list of urls
.then((list) => {
res.json(list);
}, (error) => {
console.error(error);
res.json(null);
});
});
我的一个控制器中有一个方法。控制器的目的是使用 webshot package.
打印一组 url这是有问题的代码:
router.post('/capture', function (req, res, next) {
//Check params remove
var json = JSON.parse(req.body.data);
var promise = new Promise(function (resolve, reject) {
var totalImages = Object.keys(json).length;
var arrayListUrlImages = new Array(totalImages);
var counter = 0;
var completeDir = dir + ''; //Directory URL
for (var value of json) {
var url = 'http://example.com/' + id + '/' + value.anotherValue;
var folder = completeDir + id + '/' + value.anotherValue + '.jpg';
//Options for capturing image
var options = {
renderDelay: 1000,
quality: 100,
phantomConfig:
{
'local-to-remote-url-access': 'true',
'ignore-ssl-errors': 'true'
}
};
var anotherValue = value.anotherValue;
(function (anotherValue) {
webshot(url, folder, options, function (err) {
// screenshot now saved
if (err === null) {
var urlImage = "http://example.com/images/" + id + "/" + anotherValue + ".jpg";
arrayListUrlImages.push(urlImage);
counter++;
console.log("Counter: " + counter);
if (counter === totalImages) {
resolve(arrayListUrlImages);
}
}
else {
reject(err);
}
});
})(anotherValue);
}
}).then(function (arrayImages) {
res.send(arrayImages);
}).catch(function (errorVale) {
res.send(null);
});
});
这段代码没有问题...但我想做得更好。我不知道有多少 URL 需要检查(这是重要的细节,因为我需要为每个或类似的 做一个检查)。
我读过关于 async package... 是否更好的选择是将此代码移动到类似 async.parallel 的位置?我可以在我的代码中使用 yield 吗?
谢谢!
既然你用的是Promise,我推荐Promise.all。
It returns a promise that resolves when all of the promises in the iterable argument have resolved, or rejects with the reason of the first passed promise that rejects.
看来它解决了你的问题。
示例:
downloadOne = url => new Promise(resolve => {
webshot(url, ....., (err, res) => resolve(res));
})
router.post('/capture', function (req, res, next) {
var urls = JSON.parse(req.body.data);
Promise.all(urls.map(downloadOne)).then(req.send);
}
老实说,您的代码看起来不错。
如果您不打算在此处添加更多逻辑,请保持原样。
可以做得更好的是将其迁移到 ES6 语法并提取另一个值函数,但我不知道这是否适用于您的情况。
对于这样简单的示例,您不需要使用 async
。使用原生承诺:
router.post('/capture', function (req, res, next) {
//Check params remove
const json = JSON.parse(req.body.data);
Promise.all(Object.getOwnPropertyNames(json).map((key) => {
var value = json[key];
var url = 'http://example.com/' + id + '/' + value.anotherValue;
var folder = completeDir + id + '/' + value.anotherValue + '.jpg';
//Options for capturing image
var options = {
renderDelay: 1000,
quality: 100,
phantomConfig:
{
'local-to-remote-url-access': 'true',
'ignore-ssl-errors': 'true'
}
};
return new Promise((resolve, reject) => {
webshot(url, folder, options, function (err) {
if (err) {
reject(err);
return;
}
var urlImage = "http://example.com/images/" + id + "/" + anotherValue + ".jpg";
resolve(urlImage);
}
});
}))
.then((listOfUrls) => {
res.json(listOfUrls); // List of URLs
}, (error) => {
console.error(error);
res.json(null);
});
});
这是一个基于内部函数的代码流示例:
router.post('/capture', function (req, res, next) {
// Definitions
// Load image
function loadImage(value) {
var url = 'http://example.com/' + id + '/' + value.anotherValue;
var folder = completeDir + id + '/' + value.anotherValue + '.jpg';
//Options for capturing image
var options = {
renderDelay: 1000,
quality: 100,
phantomConfig:
{
'local-to-remote-url-access': 'true',
'ignore-ssl-errors': 'true'
}
};
return webshotPromise(url, folder, options);
}
// Load whebshot as a promise
function webshotPromise(url, folder, options) {
return new Promise((resolve, reject) => {
webshot(url, folder, options, function (err) {
if (err) {
reject(err);
}
var urlImage = "http://example.com/images/" + id + "/" + anotherValue + ".jpg";
resolve(urlImage);
}
});
}
// The method flow
const json = JSON.parse(req.body.data);
// Get json keys and iterate over it to load
Promise.all(
Object.getOwnPropertyNames(json).map(key => loadImage(json[key]))
)
// Got list of urls
.then((list) => {
res.json(list);
}, (error) => {
console.error(error);
res.json(null);
});
});