Future (Promise)

The Future pattern allows starting a computation in the background and retrieve the result later, allowing other work to continue in the meantime.

graph LR
    start["Start Task"] --> initiate["Initiate Future (async)"]
    initiate --> task["Do Task (in goroutine)"]
    task --> future["Future (holds result)"]
    future --> result["Get Result (from future)"]
    result --> done["Done"]

Applicability

  • Deferred Computation. When you know you’ll need a result later, but don’t want to block the current execution.

  • Concurrent I/O Operations. Useful for performing multiple network requests or disk reads in parallel.

  • Parallel Task Execution. When you can execute independent tasks simultaneously to improve performance.

  • UI or API Responsiveness. Helps avoid blocking the main thread or request handler while a background job is running.

  • Lazy Initialization. Start expensive setup only when the result is eventually needed, without blocking early.

Example

package main

import (
	"fmt"
	"time"
)

type data struct {
	Body  string
	Error error
}

func main() {
	future1 := future("https://example1.com")
	future2 := future("https://example2.com")

	fmt.Println("Requests started")

	body1 := <-future1
	body2 := <-future2

	fmt.Printf("Response 1: %v\n", body1)
	fmt.Printf("Response 2: %v\n", body2)
}

func future(url string) <-chan data {
	resultChan := make(chan data, 1)

	go func() {
		body, err := doGet(url)

		resultChan <- data{Body: body, Error: err}
	}()

	return resultChan
}

func doGet(url string) (string, error) {
	time.Sleep(time.Millisecond * 200)
	return fmt.Sprintf("Response of %s", url), nil
}

This site is open source! You can contribute or suggest changes by editing the GitHub repository.
Copyright © 2025. Distributed by an MIT license.