65.9K
CodeProject is changing. Read more.
Home

Ignoring Operation Result when using F# async Computation Expression

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2 votes)

Mar 6, 2019

CPOL
viewsIcon

9394

Simple pitfall where C# developers trying out F# might fail when writing async code

Using the Code

Consider this simple code downloading page contents using Puppeteer-sharp.

let renderHtml = async {
    BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision) |> Async.AwaitTask |> ignore
    let options = LaunchOptions()
    options.Headless <- true
    let! browser = Puppeteer.LaunchAsync(options) |> Async.AwaitTask
    let! page = browser.NewPageAsync() |> Async.AwaitTask
    page.GoToAsync("https://i.ua") |> Async.AwaitTask |> ignore    
    return! page.GetContentAsync() |> Async.AwaitTask    
}

Since we actually don't care about download browser result, we naturally would expect that our line...

BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision) |> Async.AwaitTask |> ignore

...would be equivalent to this C# code:

await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);

However, when we execute the following method, we get Aggregate<wbr />Exception which in turn contains the following inner exception: "Chromium revision is not downloaded. Run BrowserFetcher.DownloadAsync or download Chromium manually". Seems like we've called...

let! browser = Puppeteer.LaunchAsync(options) |> Async.AwaitTask

...without waiting for BrowserFetcher result.

And indeed, in order to await async call, we have to use let! construct. The code below works as expected:

let renderHtml = async {
    let! _ = BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision) |> Async.AwaitTask
    let options = LaunchOptions()
    options.Headless <- true
    let! browser = Puppeteer.LaunchAsync(options) |> Async.AwaitTask
    let! page = browser.NewPageAsync() |> Async.AwaitTask
    let! _ = page.GoToAsync("https://i.ua") |> Async.AwaitTask    
    return! page.GetContentAsync() |> Async.AwaitTask    
}

Note how we use underscore to show that the variable value is ignored.

History

  • 6th March, 2019: Initial version