Async Operations and Promises
In This Topic
Most of the asynchronous operations in NOV return instances of the NPromise<TResult> generic class. A promise represents the eventual successful completion or failure of an asynchronous operation. Each promise allows you to subscribe function handlers for the two possible outcomes of the operation, by calling one of its Then methods:
NPromise example |
Copy Code
|
// invoke some async operation that returns a promise
NPromise<string> promise = GetAsyncString();
// subscribe for the operation outcomes
promise.Then(
delegate (string str)
{
Console.WriteLine("Operation succeeded");
},
delegate (Exception ex)
{
Console.WriteLine("Operation failed");
});
|
The promise state is accessible from its State property, which return a value from the ENPromiseState enumeration:
ENPromiseState |
Description |
Pending |
The promise has not been resolved yet./td> |
Fulfilled |
The promise has been successfully resolved. |
Rejected |
The promise has resolved with error. |
The promise state is accessible from its State property, which return a value from the ENPromiseState enumeration:
Core Methods - Then, Catch, Finally
The most commonly used method of a promise is the Then method - it allows you to install a pair of callback functions - one in case the promise is fulfilled and one in case the promise is rejected.
The Catch method is a variation of the Then method, which generally installs only an error handler for the promise.
The Finally method is also a variation of the Then method, which internally handles both the fulfilled and rejected cases to call a function that is invoked when the promise is resolved, regardless of whether the resolve was successful or not.
Both the Catch and Finally method are usually used in chained promises.
Undefined Promises
Certain promises need not be associated with a result of a certain type. Because the NPromise<TResult> class is a generic type, for such cases the NUndefined class is used. These promises are called undefined promises. The NUndefined class has a singleton instance accessible from its Instance property - you can use it to return or pass undefined values.
Resolving Promises
You can resolve a pending promise by calling either the Fulfill or Reject methods. Both methods will throw an exception, if the promise is already resolved.
The Fulfill method takes as argument the result of the promise. The result of a fulfilled promise can be accessed at any time from the Result property.
The Reject method takes as argument an exception that describes the rejection error. The error of a rejected promise can be accessed at any time from the Error property.
Chaining Promises
It is a common practice to perform a series of asynchronous operations each subsequent one of which depends on the previous one. This is achieved with the help of promise chaining, like in the following example:
Chaining Promises |
Copy Code
|
NFile file = NApplication.FileSystemService.GetFile("C:\\Test.txt");
Stream theStream = null;
file.Exists().ThenPromise<Stream>(delegate (bool exists){
if (!exists)
throw new Exception("Faild does not exist");
return file.OpenRead();
}).ThenPromiseUndefined(delegate (Stream stream){
theStream = stream;
StreamReader reader = new StreamReader(theStream);
string fileContent = reader.ReadToEnd();
Console.WriteLine(fileContent);
}).CatchPromiseUndefined(delegate (Exception ex){
Trace.WriteLine("Failed to load file");
})
.Finally(delegate (){
if (theStream != null)
{
theStream.Close();
}
});
|
Aggregate Promises
Aggregate promises are such promises that aggregate other promises. Aggregate promises are created via helper methods in the NAggregatePromise static class. The following table describes the aggregate promises:
Method |
Return Value |
Description |
All |
NPromise<object[]> |
The All method takes an array of promises, and returns a single Promise that contains an array of the results of the input promises.
The returned promise will fulfill when all of the input's promises have fulfilled.
It rejects immediately upon any of the input promises rejecting, and will fail with this first failure exception. |
Any |
NPromise<object> |
The Any method takes an array of promises, and returns a single promise that fulfills with the result of the first promise that is fulfilled.
If no promises fulfill (i.e. all of the promises are rejected), then the returned promise is rejected with an AggregateException, that groups together the individual exceptions.
Essentially, this method is the opposite of the All method. |
AllResolved |
NPromise<bool[]> |
The AllResolved method returns a promise that resolves after all of the given promises have either fulfilled or rejected,
with an array of boolean values each of which describes whether the promise at the specified ordinal fulfilled or rejected. |
Race |
NPromise<object> |
The Race method returns a promise that fulfills or rejects as soon as one of the promises fulfills or rejects, with the value or reason from that promise. |
The following example demonstrates the usage of aggregate promises.
Aggregate Promise Example |
Copy Code
|
NFile file1 = NApplication.FileSystemService.GetFile("C:\\Test1.txt");
NFile file2 = NApplication.FileSystemService.GetFile("C:\\Test2.txt");
NAggregatePromise.All(file1.Exists(), file2.Exists()).Then(
delegate (object[] results) {
bool file1Exists = (bool)results[0];
bool file2Exists = (bool)results[1];
if (file1Exists && file2Exists) {
Console.WriteLine("Both files exist");
}
else if (file1Exists) {
Console.WriteLine("Only file1 exists");
}
else if (file2Exists) {
Console.WriteLine("Only file2 exists");
}
else {
Console.WriteLine("Both files do not exist");
}
},
delegate (Exception ex) {
Console.WriteLine("Failed to determine whether file1 and file2 exist");
});
|