Asynchronous HTTP programming
Interfaces provided by Pistaches are asynchronous and non-blocking. Asynchronous programming allows for code to continue executing even if the result of a given call is not available yet. Calls that provide an asynchronous interface are referred to asynchronous calls.
An example of such a call is the send()
function provided by the ResponseWriter
interface. This function returns the number of bytes written to the socket file descriptor associated to the connection. However, instead of returning directly the value to the caller and thus blocking the caller, it wraps the value into a component called a Promise
.
A Promise
is the Pistache’s implementation of the Promises/A+ standard available in many JavaScript implementations. Simply put, during an asynchronous call, a Promise
separates the launch of an asynchronous operation from the retrieval of its result. While the asynchronous might still be running, a Promise<T>
is directly returned to the caller to retrieve the final result when it becomes available. A so called continuation can be attach to a Promise
to execute a callback when the result becomes available (when the Promise
has been resolved or fulfilled).
auto res = response.send(Http::Code::Ok, "Hello World");res.then( [](ssize_t bytes) { std::cout << bytes << " bytes have been sent\n" }, Async::NoExcept);
The then()
member is used to attach a callback to the Promise
. The first argument is a callable that will be called when the Promise
has been succesfully resolved. If, for some reason, an error occurs during the asynchronous operation, a Promise
can be rejected and will then fail. In this case, the second callable will be called. Async::NoExcept
is a special callback that will call std::terminate()
if the promise failed. This is the equivalent of the noexcept
keyword.
Other generic callbacks can also be used in this case:
Async::IgnoreException
will simply ignore the exception and let the program continueAsync::Throw
will "rethrow" the exception up to an eventual promise call-chain. This has the same effect than thethrow
keyword, except that it is suitable for promises
Exceptions in promises callbacks are propagated through an exception_ptr
. Promises can also be chained together to create a whole asynchronous pipeline:
auto fetchOp = fetchDatabase();fetchOp .then( [](const User& user) { return fetchUserInfo(user); }, Async::Throw) .then( [](const UserInfo& info) { std::cout << "User name = " << info.name << '\n'; }, [](exception_ptr ptr) { std::cerr << "An exception occured during user retrieval\n";});
Line 5 will propagate the exception if fetchDatabase()
failed and rejected the promise.