Promises Tutorial by Irakli Nadareishvili
  • Introduction
  • Turning Callbacks Into Promises
  • Chain Parallel with Sequential
  • Conditions and Promises
  • Keeping Promise Chains Flat
  • Async and Await
  • Async/Await & Express, Mocha etc.
  • One More Thing (Go)...
  • One More Thing (Python)...
  • One More Thin (Nim)…
Powered by GitBook
On this page

Was this helpful?

One More Thing (Go)...

If you are like us and you love Node, but you also enjoy Go, it could be fun to compare the examples we completed in this tutorial to equivalent code in Go. Below is an earlier Node example, now implemented in Go. It hopefully gives a sense of how Go and goroutines-based concurrency are different from Node and Promises-based, asynchronous concurrency:

Chain Parallel with Sequential

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "os"
    "sync"

    "github.com/buger/jsonparser"
)

const baseURL = "https://www.googleapis.com/books/v1/volumes?q="

type fnBytes func([]byte)

/** Query authors of a book. Concurrently query how many books each one of them
have published. Display final scoreboards, once all the results are in. */
func main() {
    defer panicHandler()

    type AuthorStatistics struct {
        author string
        count  int
    }
    var stats AuthorStatistics
    var scoreboard = []AuthorStatistics{}

    const isbn = "1491956224" // "Microservice Architecture"
    authors := bookAuthors(isbn)
    // fmt.Println("Authors: %v", authors)

    var wg sync.WaitGroup
    wg.Add(len(authors))

    for _, author := range authors {
        go func(anAuthor string) {
            defer panicHandler()
            defer wg.Done()

            numBooks, authorName := authorNumBooks(anAuthor)
            stats.author = authorName
            stats.count = numBooks
            scoreboard = append(scoreboard, stats)
        }(author)
    }

    wg.Wait()

    fmt.Printf("Publishing statistics: %+v \n", scoreboard)
}

/** panicHandler handles all the panics. If you need stack trace, uncomment the
  corresponding line */
func panicHandler() {
    if r := recover(); r != nil {
        // fmt.Printf("ERROR: %v\n\n %s", r, debug.Stack())
        fmt.Printf("ERROR: %v \n", r)
        os.Exit(1)
    }
}

/** bookAuthors returns all authors of a book */
func bookAuthors(isbn string) []string {
    bookURL := baseURL + "isbn:" + isbn

    body := queryAPI(bookURL, googleAPIError)

    authors := []string{}

    // items[0].volumeInfo.authors;
    jsonparser.ArrayEach(body, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
        valueString := string(value[:])
        authors = append(authors, valueString)
    }, "items", "[0]", "volumeInfo", "authors")

    if len(authors) == 0 {
        panic(fmt.Sprintf("no authors found for isbn: %v, with URL: %v", isbn, bookURL))
    }
    return authors
}

/** authorNumBooks returns number of books an author has published */
func authorNumBooks(authorName string) (int, string) {
    authorNameSafe := url.QueryEscape(authorName)
    apiURL := baseURL + "inauthor:\"" + authorNameSafe + "\""

    body := queryAPI(apiURL, googleAPIError)

    numBooks, err := jsonparser.GetInt(body, "totalItems")
    if err != nil {
        panic(err.Error())
    }

    return int(numBooks), authorName
}

/** queryAPI queries an HTTP API, and performs error handling */
func queryAPI(apiURL string, errHandler fnBytes) []byte {
    res, err := http.Get(apiURL)
    if err != nil {
        panic(err.Error())
    }
    defer res.Body.Close()

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err.Error())
    }

    if res.StatusCode > 399 {
        errHandler(body)
    }

    return body
}

/** googleAPIError handles any non-OK HTTP status returns */
func googleAPIError(body []byte) {
    errMsg, err := jsonparser.GetString(body, "error", "message")
    if err != nil {
        panic(err.Error())
    }
    panic(fmt.Sprintf("Google Books API Response: '%s'", errMsg))
}
PreviousAsync/Await & Express, Mocha etc.NextOne More Thing (Python)...

Last updated 5 years ago

Was this helpful?

Side note: source code of this example can be found at:

https://github.com/inadarei/golang-async