Hacklang async code example?

3.8k views Asked by At

How modify the following code to get article data and top articles asynchronously in hack ?

class ArticleController
{
    public function viewAction()
    {
        // how get
        $article = $this->getArticleData();
        $topArticles = $this->getTopArticles();
    }

    private function getArticleData() : array
    {
        // return article data from db
    }

    private function getTopArticles() : array
    {
        // return top articles from db
    }
}
2

There are 2 answers

0
Victor On BEST ANSWER

HHVM 3.6 and newer

async functions info

The two HHVM PHP language keywords that enable async functions are async and await. async declares a function as asynchronous. await suspends the execution of an async function until the result of the asynchronous operation represented by await is available. The return value of a function that await can be used upon is an object that implements Awaitable<T>.

You have an example in the documentation (1). There is a discussion about asynchronous functions in the language specification as well (2).

It actually took me some time to realize how to use and call the asynchronous functions, so I think you will find some more info useful.

We have these two functions: foo() and bar().

async function foo(): Awaitable<void> {
  print "executed from foo";
}
async function bar(int $n): Awaitable<int> {
  print "executed from bar";
  return $n+1;
}

Let's experiment some ways to call these two functions:

foo();                  // will print "executed from foo"
bar(15);                // will print "executed from bar"
$no1 = bar(15);         // will print "executed from bar"
print $no1;             // will output error, because $number is not currently an `int`; it is a `WaitHandle`
$no2 = bar(15)->join(); // will print "executed from bar"
print $no2;             // will print 16

AsyncMysqlClient tips

The connection to a MySQL database is made with AsyncMysqlClient::connect asynchronous function which returns an ExternalThreadEventWaitHandle to an AsyncMysqlConnection.

You can perform query or queryf on an AsyncMysqlConnection. Note: the data you send to a queryf is properly escaped by the function.

A query you perform on an AsyncMysqlConnection returns either an AsyncMysqlQueryResult (when the query performs ok) or AsyncMysqlQueryErrorResult (if the query goes wrong; then you can treat errors with the mysql_error(), mysql_errno() and failureType() members of this class). Both AsyncMysqlQueryResult and AsyncMysqlQueryErrorResult extend AsyncMysqlResult abstract class.


Below is a probable implementation of your class:

class ArticleController {
  private AsyncMysqlConnection $connection;
  public async function viewAction(int $articleId): Awaitable<void> {
    $this->connection = await AsyncMysqlClient::connect( /* connection data */ );
    $article = await $this->getArticleData($articleId);
  }
  public async function getArticleData(int $id): Awaitable<?Vector> {
    $articleDataQuery = await $this->connection->queryf("SELECT * FROM articles WHERE id %=d", $id);
    if($articleDataQuery instanceof AsyncMysqlQueryErrorResult) {
      throw new Exception("Error on getting data: ".$articleDataQuery->mysql_error());
    }

    // Considering that $id represents a unique id in your database, then
    // you are going to get only one row from your database query
    // so you return the first (and only) row in the query result
    if($articleDataQuery->numRows() == 1) {
      return $articleDataQuery->mapRowsTyped()[0];
    }
    return null;
  }
} 

P.S. I hope it is not too late for this answer and I hope it helps you. If you consider this useful, please, accept it.

1
Josh Watzman On

The warning from the async documentation page is relevant here:

There is currently basic support for async. For example, you can currently write basic async functions that call other async functions. However, we are currently finalizing other foundations (e.g. async database, scheduling, and memory handling APIs) which will be required to reach the full potential of async in production. We felt, though, it would be useful to introduce the concept and technology of async (even with basic functionality) in order to get developers used to the syntax and some of the technical details.

So, the raw database queries you need to actually make use of async functions are unfortunately not available yet. The documentation linked above talks some about how async functions work in general, and includes an example of coalesced fetching, something that you can do with async functions right now.

The DB API is coming eventually, but isn't available yet, sorry!