If you’re used to closure based asynchronous code, you might need to get used to the new order of execution in structured concurrency. Don’t worry though—the order will be much easier to understand.

This lesson is almost common sense, but I did not want to dive into more advanced order of execution before shortly discussing the basics.

The order of execution when defining multiple async methods

For this example, I’ve defined a new ArticleTitleFetcher which allows us to fetch the title for a given webpage:

struct ArticleTitleFetcher {

    func fetchTitle(for url: URL) async throws -> String {
        print("Fetching title for \(url)")

        let (data, _) = try await URLSession.shared.data(from: url)

        guard let htmlString = String(data: data, encoding: .utf8) else {
            throw URLError(.cannotDecodeContentData)
        }

        return extractTitle(from: htmlString) ?? "Untitled"
    }

    private func extractTitle(from html: String) -> String? {
        guard let range = html.range(of: "<title>(.*?)</title>", options: .regularExpression) else {
            return nil
        }
        return String(html[range])
            .replacingOccurrences(of: "<title>", with: "")
            .replacingOccurrences(of: "</title>", with: "")
            .trimmingCharacters(in: .whitespacesAndNewlines)
    }
}

Now, imagine fetching titles for three distinct articles:

let titleOne = try await fetcher.fetchTitle(for: URL(string: "https://www.avanderlee.com/swiftui/how-to-develop-an-app-for-ios/")!)
let titleTwo = try await fetcher.fetchTitle(for: URL(string: "https://www.avanderlee.com/swift-testing/parameterized-tests-reducing-boilerplate-code/")!)
let titleThree = try await fetcher.fetchTitle(for: URL(string: "https://www.avanderlee.com/swift/result-builders/")!)

print("Title 3: \(titleThree)")
print("Title 2: \(titleTwo)")
print("Title 1: \(titleOne)")

I’ve purposely printed the titles in a different order than the property definitions. Without looking further into this lesson, what is the correct answer:

In the above example, the answer is C: the requests will fire one by one:

Fetching title for https://www.avanderlee.com/swiftui/how-to-develop-an-app-for-ios/
Fetching title for https://www.avanderlee.com/swift-testing/parameterized-tests-reducing-boilerplate-code/
Fetching title for https://www.avanderlee.com/swift/result-builders/

This is the whole idea behind structured concurrency: asynchronous execution will flow from top to bottom in the order you expect. Any code defined after an await will only be executed once the awaited method returns. There are exceptions to this, like when using async let, which we will discuss in the next lesson.

Summary

Structured concurrency reveals the order of execution—the order you expect. You could say that code execution will ‘pause’ as long as a method is being awaited. As briefly mentioned, there are exceptions to this statement. One is async let, which we will discuss in the next lesson.