Why does Promisification fail for some methods but not all? - bluebird

The jsonix library does not follow the first argument must be an error convention so I decided to use bluebird and promisify it like so:
return new Promise(function(resolve, reject) {
try {
unmarshaller.unmarshalString(xmlResponse,
function (unmarshalled) {
...
resolve(unmarshalled);
});
}
catch (error) {
reject(error);
}
});
But this hangs indefinitely! Whereas if I simply save the xmlResponse to a file and then process it with a different method: unmarshalFile ... the promisification seems to work just fine!
return new Promise(function(resolve, reject) {
try {
unmarshaller.unmarshalFile('test1.xml',
function (unmarshalled) {
...
resolve(unmarshalled);
});
}
catch (error) {
reject(error);
}
});
So my question is why would promisification fail for one method but not another?

When I look at the code for jsonix, I don't see any callback function for .unmarshalString() and looking at the implementation, there's nothing async in the implementation and nothing that calls a callback. It just returns the answer directly. So, the function is synchronous, not async and returns its value directly as a return value.
For reference, .unmarshalURL() and .unmarshalFile() do accept the callback and do have an async implementation - .unmarshalString() is just different.
So, you don't need to use promises with unmarshaller.unmarshalString(xmlResponse) at all. You could just return the straight value:
return unmarshaller.unmarshalString(xmlResponse);
If you want to wrap it in a promise for consistency of interface among all three methods, you can do this:
try {
return Promise.resolve(unmarshaller.unmarshalString(xmlResponse));
} catch(err) {
return Promise.reject(err);
}
Or, you can use Bluebird's Promise.method() to wrap it for you:
return Promise.method(unmarshaller.unmarshalString.bind(unmarshaller, xmlResponse));

Disclaimer: I'm the author of Jsonix.
unmarshalURL and unmarshalFile are async (and have to be) but unmarshalString or unmarshalDocument are not async (and don't have to be).

Related

Async function returns two different results after another

I have written an async Flutter/Dart function which behaves unexpectedly in my opinion. Following code structure:
static Future<bool> verifySometing() async {
try {
await getCloudData().then((snapshot) {
if (snapshot.exists && snapshot.hasData) {
bool dataValid = await validateData(snapshot.data);
if (dataValid) {
print('Data is correct');
return true;
}
}
});
} catch (e) {
print('Error $e');
return false;
}
print('Something went wrong');
return false;
}
The expected result would be that the function awaits the cloud data, then awaits validation and returns true if the data is valid. In this case, the console would show the following and the function would return true:
Data is correct
What happens in practice is that the console shows the following output and the function first returns true and then false:
Data is correct
Something went wrong
This goes against anything I thought to know about funtions in Dart because I always assumed that once return is fired, the function is done. Any ideas how this happens?
The issue is with this line.
await getCloudData().then((snapshot) {
Here, instead of just awaiting, you have also attached a then callback. So in actuality, whatever you are returning is return value of the callback function ie., (snapshot) {}.
The callback function that you need to pass into the then takes that return true and gives it to us as the result of await.
So, if you would've put something like
var bool = await getCloudData().then((snapshot) { ..... });
Then this bool, would've been equal to true. That's it. No return from the your main function.
Change it to this,
var snapshot = await getCloudData();
if (snapshot.exists && snapshot.hasData) {
bool dataValid = await validateData(snapshot.data);
if (dataValid) {
print('Data is correct');
return true;
}
}
Hope, I was able to explain clearly.
There are a few of faults in your assumptions.
First, you've attached a then to the future returned by getCloudData(). This means that you aren't awaiting getCloudData(), but instead the additional future returned by getCloudData().then(...), and that future will return when the callback function passed to it completes. (And unless the first future throws an error, the callback will be called.)
Second, the callback function operates on its own scope. So this code is not doing what you think it's doing:
bool dataValid = await validateData(snapshot.data);
if (dataValid) {
print('Data is correct');
return true;
}
This return will affect the callback function, not the verifySomething function.
Given these, the order of operation is as follows:
The validateSomething function awaits getCloudData().then(...).
getCloudData() gets called.
getCloudData() returns, the callback passed to then is called.
(Assuming the snapshot has data) validateData is called.
(Assuming data is successfully validated) "Data is correct" gets printed and the callback function returns true.
validateSomething is notified that the awaited future is complete, so execution resumes.
"Something went wrong" gets printed and the validateSomething function returns false.
Generally speaking, these kinds of errors are common when mixing async/await and then patterns. Unless you know what you're doing, stick with either one or the other, preferably the async/await pattern. For example, a refactor of your code to eliminate the call to then is as follows:
static Future<bool> verifySometing() async {
try {
final snapshot = await getCloudData();
if (snapshot.exists && snapshot.hasData) {
bool dataValid = await validateData(snapshot.data);
if (dataValid) {
print('Data is correct');
return true;
}
}
} catch (e) {
print('Error $e');
return false;
}
print('Something went wrong');
return false;
}
Now that there isn't a pesky closure to deal with, return will return from validateSomething as expected and you don't need to deal with issues like callbacks and scope.

How can i convert typescript callback to promise

i want to make a method in my class. This method should connect to a MySQL database. I created my SQL code. And now I don't want to do a callback because this is old, I want to start using promises.
My function with callback (old school):
public does_player_exist(username: string, callback: any) {
this.mysql.connect();
this.mysql.query('USE devdb');
this.mysql.query('SELECT p_name FROM players WHERE p_name = "'+username+'"', (err: Error, result: any[]) {
if (result.length === 1) {
callback(true)
} else {
callback(false);
}
});
}
And here follows the method I tried to make a promise, but I failed:
public does_player_exist(username: string): Promise<boolean> {
this.mysql.connect();
this.mysql.query('USE devdb');
return this.mysql.query('SELECT p_name FROM players WHERE p_name = "'+username+'").toPromise().then((result) => {
return result.length === 1;
})
}
When I call this method:
service.does_player_exist('test').then((result) => { console.log(result) })
I hope someone can help me. Because I really don't want to be old school forever xD
Thanks in advance.
create a new Promise and resolve it / reject it in the callback functions of query. then return the promise. now does_player_exist returns a Promise object which contains for example then function
public does_player_exist(username: string, callback: any): Promise<boolean> {
this.mysql.connect();
this.mysql.query('USE devdb');
var promise = new Promise<boolean>();
this.mysql.query('SELECT p_name FROM players WHERE p_name = "'+username+'"', (err: Error, result: any[]) {
if (!err) promise.resolve(!!result.length);
else promise.reject();
});
return promise;
}
you will have to make sure that you have a Promise class available. that depends on your environment.
please be aware that without sanitizing your input (username) your application will be vulnerable and attackers could hijack your app.
Tip #1. Please use some kind of factory function to build your connection and reuse it later on.
Tip #2. Use prepared statement to prevent SQL injection.
Tip #3. Please use some promise library for that like Bluebird or Q. Most of the 3rd party promise libraries have a lot of useful utility methods to work with promises on of them is promisify. Promisify can wrap any nodejs type callback function into function which returns a promise.
Your example would look like:
// it's not a factory function*
public query() {
this.mysql.connect();
this.mysql.query('USE devdb');
return Promise.promisify(this.mysql.query.bind(this.mysql))
}
public does_player_exist(username: string): Promise<boolean> {
return this
.query('SELECT p_name FROM players WHERE p_name = ?', [username])
.then(result => result.length === 1);
}
I wrote a simple npm package to do this in a way that retains type-safety:
ts-promisify-callback
It requires you use typescript#^4.0 (upcoming release) and currently only works for callbacks in the popular format of (err, result) => {}.

What is this syntax in ES6 or ES7?

I came across this syntax which I believe is ES6 or ES7. What do these lines of code do?
module.exports = async (taskData) => {
// do stuff
}
It exports an asynchronous arrow function which takes in an argument taskData. The asynchronous function is new syntax that is set to come with this year's release, ES2017, called the async function, though the rest of the code is ES6 (ES2015) and ES5 (ES2011). It goes hand-in-hand with await and returns a Promise.
It's primarily useful to clean up promise chains, where the code can get really messy. Consider this example using promises, found here:
function loadStory() {
return getJSON('story.json').then(function(story) {
addHtmlToPage(story.heading);
return story.chapterURLs.map(getJSON)
.reduce(function(chain, chapterPromise) {
return chain.then(function() {
return chapterPromise;
}).then(function(chapter) {
addHtmlToPage(chapter.html);
});
}, Promise.resolve());
}).then(function() {
addTextToPage("All done");
}).catch(function(err) {
addTextToPage("Argh, broken: " + err.message);
}).then(function() {
document.querySelector('.spinner').style.display = 'none';
});
}
The example above fetches a story, and iterates through all the chapters and adds them to the HTML. It works, but it can be very messy and hard to follow if you've got lots of stuff to do. Instead, you can use async and await, which is just syntactic sugar, but makes it much more clean:
async function loadStory() {
try {
let story = await getJSON('story.json');
addHtmlToPage(story.heading);
for (let chapter of story.chapterURLs.map(getJSON)) {
addHtmlToPage((await chapter).html);
}
addTextToPage("All done");
} catch (err) {
addTextToPage("Argh, broken: " + err.message);
}
document.querySelector('.spinner').style.display = 'none';
}
The above is (in my opinion) way more clean and easy to follow, versus the messy promise chain in the first example.
This is an async function which is set to return Promise as #Andrew says.
It is using Arrow Function syntax.
()=>{}
This function is in ES6 and does not define its own this context and any use of this will refer to the outer scope.
Async await syntax is set to be supported when ES2017 is released. Your code is essentially a function that returns a promise. Additionally, the async keyword allows for syntactic sugar when working with promises by use of the await keyword.
The => part is called an arrow function which again is a syntactic sugar for the most part. It is part of ES6.
Your function
module.exports = async (taskData) => {
// do stuff
}
... is almost the same as:
module.exports = function(taskData) {
return new Promise(function() {
// do stuff
if (err) reject(err)
resolve(your return value)
}
}
Note: the main difference is just the binding of the this keyword via the arrow function.

Default Return Value for Resolved Promise

I'm learning about writing functions that return promises in ES6, for example:
function async() {
return new Promise(function (resolve, reject) {
if (doStuff()) {
resolve(value);
} else {
reject(error);
}
}
}
Sometimes, there is no useful value to pass back in resolve(value). In these cases, what should be the default value to return?
Just like functions that don't have a return statement do return undefined, you should return a promise for undefined. You can either explicitly pass it into resolve or simply omit the argument, which will default to undefined as well.
You can just use resolve() and reject() without specifying any argument.

Node.js - process.nextTick and parseJSON

What's the most performant way to parse JSON in Node.js?
What's the advantage of using process.nextTick and slightly delaying the answer in the following snippet and shouldn't the whole try/catch be encapsulated into process.nextTick?
function parseJSON(json, done) {
try {
var result = JSON.parse(json);
process.nextTick(function() { done(null, result); });
} catch (err) {
process.nextTick(function() { done(err); });
}
}
First, because JSON.parse is synchronous, there's no point in using a callback.
These two blocks of code essentially do the same thing. The bottom one is more efficient:
parseJSON(json, function(err, result) {
if (err) {
//ERROR
}
else {
//PARSED
}
});
vs
try {
var result = JSON.parse(json);
//PARSED
}
catch (e) {
//ERROR
}
Now onto your actual question(s):
What's the advantage of using process.nextTick...
Basically there is no "advantage" except that if you don't use process.nextTick then your function call becomes more synchronous. Take this example for instance:
console.log('1');
parseJSON(json, function(err, result) {
console.log('parsed');
});
console.log('2');
When using process.nextTick you'll get this output:
1
2
parsed
This happens because process.nextTick puts the callback function at the end of the event loop. Meaning it'll let other things happen first then execute the callback.
If you didn't use process.nextTick then you'd get this output:
1
parsed
2
This happens because parseJSON won't exit until the callback is called.
Both versions are valid, but with callbacks you usually to want them to be truly asynchronous.
As for the try-catch, it's fine where it's at if you're trying to catch errors coming from JSON.parse. Since you appear to want to handle the errors (because you're passing the error parameter to the callback if it throws an exception) then I'd say it's correct as is.
First of all
. process.nextick is async... Try catch may not work as you expext.. JSON.parse is preferred way to parse json string
--> What's the most performant way to parse JSON in Node.js?
JSON stream probably, becasue of the low memory footprint.
See the work done by dominictarr or mafintosh
https://github.com/mafintosh/json-format-stream
https://github.com/mafintosh/through-json
https://github.com/dominictarr/JSONStream