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.
Related
I have a function that expands every RowCol object in a FlexGridDetailProvider upon click. Right now, performance is bad with the way data binding works on FlexGrid rows, so I'm looking to improve performance by parallelizing each statement in the for loop.
Here's the typescript function:
if (thisDetailProvider!= null) {
setTimeout(() => {
try {
for (var t = 0; t < grid.rows.length; t++) {
if (thisDetailProvider.isDetailAvailable(t)) {
thisDetailProvider.showDetail(t);
this.gridSelectionService.clearSelectionFromGrids(thisDetailProvider.grid);
}
}
} catch (err) { console.log(err); }
}, 100);
}
I'd like the solution to be as simple as using the Parallel.For loop provided with C#. The solutions I've found so far require turning the event binding function into an asynchronous function, but I'd like to avoid introducing that complexity if there is a simpler way.
You can use async function to achieve the reduced code complexity. It is same as promise.
// `async` function | define a function start with `async` keyword
async myAsyncFunc() {
// #1 `async` ensures that the function returns a promise,
// even without explicitly return
return 123;
// #2 we can also `explicitly` return a promise
// this works same as above return
// return Promise.resolve(123);
// we can do both the ways but
// as `async` ensures that the function returns a promise
// so why to write extra code to return explicitly
}
// calling a function - and to get return result call then()
// the function inside then() will return the value
myAsyncFunc().then((returnVal) => {
console.log(returnVal); // 123
});
async yourFunction(){
for (var t = 0; t < grid.rows.length; t++) {
if (thisDetailProvider.isDetailAvailable(t)) {
thisDetailProvider.showDetail(t);
this.gridSelectionService.clearSelectionFromGrids(thisDetailProvider.grid);
}
}
}
In your case, I guess you can ignore the returning part which involves then
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.
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.
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).
How can execute a function after a number of ajax requests have all completed regardless of whether they succeeded or error-ed out?
I've been trying to use $.when.apply(this, array) to pass an array of deferred jqXHR objects. However just like the docs say
In the multiple-Deferreds case where one of the Deferreds is rejected, jQuery.when immediately >fires the failCallbacks for its master Deferred. Note that some of the Deferreds may still be >unresolved at that point.
How can leverage jQuery deferred objects to always wait for all the ajax calls to finish?
Maybe I should create my own deferred that will wrap all the other deferreds? If so I'm not quite clear how to set that up.
In the spirit of how the Promise specification is likely going for the future with a PromiseInspection object, here's a jQuery add-on function that tells you when all promises are done, whether fulfilled or rejected:
(function() {
// pass either multiple promises as separate arguments or an array of promises
$.settle = function(p1) {
var args;
if (Array.isArray(p1)) {
args = p1;
} else {
args = Array.prototype.slice.call(arguments);
}
return $.when.apply($, args.map(function(p) {
// make sure p is a promise (it could be just a value)
p = wrapInPromise(p);
// Make sure that the returned promise here is always resolved with a PromiseInspection object, never rejected
return p.then(function(val) {
return new PromiseInspection(true, val);
}, function(reason) {
// Convert rejected promise into resolved promise by returning a resolved promised
// One could just return the promiseInspection object directly if jQuery was
// Promise spec compliant, but jQuery 1.x and 2.x are not so we have to take this extra step
return wrapInPromise(new PromiseInspection(false, reason));
});
})).then(function() {
// return an array of results which is just more convenient to work with
// than the separate arguments that $.when() would normally return
return Array.prototype.slice.call(arguments);
});
}
// utility functions and objects
function isPromise(p) {
return p && (typeof p === "object" || typeof p === "function") && typeof p.then === "function";
}
function wrapInPromise(p) {
if (!isPromise(p)) {
p = $.Deferred().resolve(p);
}
return p;
}
function PromiseInspection(fulfilled, val) {
return {
isFulfilled: function() {
return fulfilled;
}, isRejected: function() {
return !fulfilled;
}, isPending: function() {
// PromiseInspection objects created here are never pending
return false;
}, value: function() {
if (!fulfilled) {
throw new Error("Can't call .value() on a promise that is not fulfilled");
}
return val;
}, reason: function() {
if (fulfilled) {
throw new Error("Can't call .reason() on a promise that is fulfilled");
}
return val;
}
};
}
})();
Then, you can use it like this:
$.settle(promiseArray).then(function(inspectionArray) {
inspectionArray.forEach(function(pi) {
if (pi.isFulfilled()) {
// pi.value() is the value of the fulfilled promise
} else {
// pi.reason() is the reason for the rejection
}
});
});
Keep in mind that $.settle() will always fulfill (never reject) and the fulfilled value is an array of PromiseInspection objects and you can interrogate each one to see if it was fulfilled or rejected and then fetch the corresponding value or reason. See the demo below for example usage:
Working demo: https://jsfiddle.net/jfriend00/y0gjs31r/