I need to create a render method to build html blocks into a string.
It seems to work but I used the notorious "new Promise" and I wanted to know if what I've done is either correct or not:
async render(req, res) {
const locals = await this.execute(req); // DB operation, retrieve context
return new Promise((resolve, reject) => {
try {
return res.render('my-view', { ...locals, layout: null }, (err, html) => {
if (err) {
return reject(err);
}
return resolve(html);
});
} catch (err) {
return reject(err);
}
});
}
Thank you!
The new Promise constructor implicitly catches (synchronous) exceptions from the executor callback, so that try/catch is not needed. Also, the return value is ignored. You'd write just
async render(req, res) {
const locals = await this.execute(req); // DB operation, retrieve context
return new Promise((resolve, reject) => {
res.render('my-view', { ...locals, layout: null }, (err, html) => {
if (err) reject(err);
else resolve(html);
});
});
}
Related
When an error/rejection occurs in detectingDog or detectingDog, the error is successfully handled by the .catch(error of the Promise.all() but I want the error to be directly handled by the catch (err) of the try structure.
How can I do this ?
PS: I have already tried to get rid of the .catch(error but then the Promise.all() hangs forever
try {
function detectingDog(bufferedData) {
return new Promise((resolve, reject) => {
package.detectDog(bufferedData, function(error, data) {
if (error) {
reject(error);
} else {
return resolve(data);
}
});
});
}
function detectingCat(bufferedData) {
return new Promise((resolve, reject) => {
package.detectCat(bufferedData, function(error, data) {
if (error) {
reject(error);
} else {
return resolve(data);
}
});
});
}
Promise.all([
detectingDog(param1),
detectingCat(param2)
]).then(responseData => {
callback(undefined, responseData);
}).catch(error => {
// (1) I need to pass the error to the outer structure where error handling is done
});
} catch (err) {
console.log(err);
// handing of the inner error (2) here
callback(err);
}
Thanks!
...but I want the error to be directly handled by the catch (err) of the try structure.
You can't do that in a non-async function, because control has already left the try/catch by the time that rejection occurs, which is after whatever function this code is in (if any) has returned.
In an async function, you can use await on a promise, which will make a rejection throw, so it would go to your try/catch. So you could do the following, but keep reading because it's fairly odd:
// In an `async` function
try {
function detectingDog(bufferedData) {
return new Promise((resolve, reject) => {
package.detectDog(bufferedData, function(error, data) {
if (error) {
reject(error);
} else {
return resolve(data);
}
});
});
}
function detectingCat(bufferedData) {
return new Promise((resolve, reject) => {
package.detectCat(bufferedData, function(error, data) {
if (error) {
reject(error);
} else {
return resolve(data);
}
});
});
}
const responseData = await Promise.all([
detectingDog(param1),
detectingCat(param2)
]);
callback(responseData);
} catch (err) {
console.log(err);
callback(err);
}
...but it doesn't make a lot of sense to go to the trouble of converting callback APIs to promises if you're just going to provide a callback-based API to your caller. Just return a promise. That makes the whole try/catch disappear:
// No need for these to be nested
function detectingDog(bufferedData) {
return new Promise((resolve, reject) => {
package.detectDog(bufferedData, function(error, data) {
if (error) {
reject(error);
} else {
resolve(data); // No need for `return`
}
});
});
}
function detectingCat(bufferedData) {
return new Promise((resolve, reject) => {
package.detectCat(bufferedData, function(error, data) {
if (error) {
reject(error);
} else {
resolve(data);
}
});
});
}
function example(param1, param2) {
return Promise.all([
detectingDog(param1),
detectingCat(param2)
]);
}
You have two options here.
If you really need the try/catch block you will need to run your code in an async function, leveraging the fact that awaiting a rejected Promise will throw an error in this context:
(async function () { // you might not need the immediately invoking function wrapper depending on your context
try {
function one(bufferedData) {
// return a promise
}
function two(bufferedData) {
// return a Promise
}
const responseData = await Promise.all([
one(param1),
two(param2)
])
callback(undefined, responseData)
} catch (err) {
console.log(err);
// handing of the inner error (2) here
callback(err)
}
})()
Alternatively, you can also just handle the error in the catch block of your Promise chain:
function one(bufferedData) {
// return a promise
}
function two(bufferedData) {
// return a Promise
}
Promise.all([
one(param1),
two(param2)
])
.then((responseData) => {
callback(undefined, responseData)
})
.catch((err) => {
console.log(err);
// handing of the inner error (2) here
callback(err)
})
This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 2 years ago.
I have the following code on a server:
let tmpFileName;
// GET
app.get('/clicked', async (req, res) => {
let nullOutput = writeTmpFile("hello, world!");
await deleteTmpFile();
console.log("Hurray, finished!");
res.send({result:nullOutput});
})
function writeTmpFile(content){
tmpFileName = "tmp" + Math.random().toString() + "tsl";
return new Promise(resolve => {
fs.writeFile(tmpFileName, content, function (err) {
if (err) throw err;
console.log('Temp file creation successful.');
});
})
}
function deleteTmpFile(spec){
return new Promise(resolve => {
fs.unlink(tmpFileName, function (err) {
if (err) throw err;
console.log('Temp file deletion successful.');
});
})
}
However, in my console output, I only get
Temp file creation successful.
Temp file deletion successful.
However, if I delete await deleteTempFile(), then Hurray, finished! shows up on the console.
And more generally, how do I debug these patterns of problems?
Why is this happening?
I have rewritten your code, to showcase how to use promises.
Promise callback gets two functions as arguments: resolve and reject.
You should call resolve when operation finishes with success, and reject when it fails.
// I moved `tmpFileName` variable from here into the request handler,
// because it was "global" and would be shared between requests.
app.get('/clicked', async (req, res) => {
let tmpFileName = "tmp" + Math.random().toString() + "tsl"
let writingResult = await writeTmpFile(tmpFileName, "hello, world!")
let deletionResult = await deleteTmpFile(tmpFileName)
res.send({ writingResult, deletionResult })
console.log("Hurray, finished!")
})
function writeTmpFile (filename, content) {
return new Promise((resolve, reject) => {
fs.writeFile(filename, content, function (err) {
// on error reject promise with value of your choice
if (err) reject(err)
// on success resolve promise with value of your choice
resolve('Temp file creation successful.')
})
})
}
function deleteTmpFile (filename) {
return new Promise((resolve, reject) => {
fs.unlink(filename, function (err) {
if (err) reject(err)
resolve('Temp file deletion successful.')
})
})
}
For working with the file you can use writeFileSync instead writeFile. (Reference).
For multiple Promise you can use the Promise.all method.
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
from MDN
I would like to get my data out from the sqlite db.each function using the promise object and the async/await I tried to do it but I don't really understand how to do it and I would like some explanations
my code below :
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('./data.sqlite', (err) => {
if (err) {
console.error(err.message);
}
console.log('Connected to the database');
});
function request (req) {
new Promise(function (resolve, reject) {
db.each(req, function (err, row) {
if (err)
reject(err);
else
data.push(row);
}, function (err, n) {
if (err) {
reject(err);
}
else
resolve(data);
});
});
}
data = await request("select * from user "); //I'm getting errors here
db.close((err) => {
if (err) {
return console.error(err.message);
}
console.log('Close the database connection');
});
await can only be used inside an async function. Create an async function, inside this function, await the promise returned by request function
async function makeRequest() {
data = await request("select * from user ");
}
and you need to return the promise from request function so that it can be awaited
function request (req) {
return new Promise(function (resolve, reject) {
// code
});
}
try {
const promise = new Promise(async (resolve, reject) => {
reject('oe')
})
.catch(async (err) => {
console.log('bbbbb', err)
throw err
})
} catch (err) {
console.log('aaaaa', err)
}
Is is possible to make aaaaa loggable
In general, it doesn't make sense to pass an async function into a promise's then or catch function. And it never makes sense to pass one into the promise constructor. If you're going to go async, do it earlier. Also, when you want a rejected promise for testing, etc., just use Promise.reject('oe').
In order to catch an error from an async function with a try/catch, you must be in an async function. In that case, the minimal change to your example would be to await the result of the call to catch:
// Assuming this is in an `async` function, making only minimal changes
try {
const promise = new Promise(async (resolve, reject) => {
reject('oe')
})
.catch(async (err) => {
console.log('bbbbb', err)
throw err
})
await promise; // ***
} catch (err) {
console.log('aaaaa', err)
}
If you aren't in an async function, you can't use try/catch to catch errors from promises (which includes from an async function call, since they return promises). Instead, you have to use the promise returned by catch:
// Assuming this is NOT in an `async` function, making only minimal changes
const promise = new Promise(async (resolve, reject) => {
reject('oe')
})
.catch(async (err) => {
console.log('bbbbb', err)
throw err
})
.catch(err => {
console.log('aaaaa', err)
})
Making larger changes, if you're already in an async function, get rid of the then and catch calls:
// Assuming this is in an `async` function
try {
try {
await Promise.reject('oe');
} catch (innerError) {
console.log('bbbbb', innerError);
throw innerError;
}
} catch (outerError) {
console.log('aaaaa', outerError);
}
You can use async/await:
async function test() {
try {
const promise = await new Promise(async (resolve, reject) => {
reject('oe')
}).catch(async err => {
console.log('bbbbb', err)
throw err
})
} catch (err) {
console.log('aaaaa', err)
}
}
test()
I have the following async function:
async function readFile () {
let content = await new Promise((resolve, reject) => {
fs.readFile('./file.txt', function (err, content) {
if (err) {
return reject(err)
}
resolve(content)
})
})
console.log(content)
}
readFile()
This runs just fine. It outputs the file buffer to the console as expected. But now, if I try to instead return the value:
async function readFile () {
let content = await new Promise((resolve, reject) => {
fs.readFile('./file.txt', function (err, content) {
if (err) {
return reject(err)
}
resolve(content)
})
})
return content
}
console.log(readFile())
I now get:
Promise { <pending> }
Why is this? Why can you use a value inside that function but when you return it out of the function it's now a Promise?
How do you actually make use of this in a normal workflow? For example, lets say I wanted to check if a file exists, then read in the file, then update some database with the content, the synchronous pseudo code would look something like this:
if (fileExists(path)) {
buffer = readFile(path)
updateDatabase(buffer)
}
That workflow consists of 3 individual async operations. How would you do something like this with async/await? Is the key that you have to have your entire script wrapped in an async function?
async function doSomething () {
if (fileExists(path)) {
buffer = readFile(path)
updateDatabase(buffer)
}
}
(Keep in mind that is just pseudo-code but hopefully its gets my point across).
All async functions return a promise as was mentioned in the comments. You could therefore re-write your readFile function like this:
function readFile() {
return new Promise((resolve, reject) => {
fs.readFile('./file.txt', function (err, content) {
if (err) {
return reject(err)
}
resolve(content)
})
})
}
You would then consume the return value of readFile via await:
console.log(await readFile()) // will log your actual file contents.
The usual workflow with this paradigm is to break your async operations into separate functions that each return a promise, and then run them all inside a broader async function, much like you suggest, but with awaits and some error handling like so:
async function doSomething () {
try {
const fileCheck = await fileExists(path)
if (fileCheck) {
const buffer = await readFile(path)
await updateDatabase(buffer)
// Whatever else you want to do
}
} catch (err) {
// handle any rejected Promises here.
}
}
const serchContentXmlFile = async (path, content) => {
return new Promise((resolve, reject) => {
fs.readFile(path, function (err, data) {
if (err) {
return reject(err)
}
resolve(data.indexOf(content))
})
})
}
await serchContentXmlFile("category.xml",xmlUrl);