Async/Await
JaxNode July 2021
About Me
fek.io/blog
youtube.com/c/polyglotengineer
github.com/davidfekke
@jaxnode @polyglotengine1
Async/Await
- Asynchronous Programming
- These are two magic keywords
- Being added to more languages
- Just added to Rust
- Being Added to Swift
Concurrency is Hard!
Concurrency should be as easy as riding a bicycle
Why is concurrency important?
AMD Ryzen has 32 Cores
State of Computing today
- Processors aren't getting faster
- Still adding more transistors to piece of silicon
- More cores being added to processors
- Speed is coming from being able to do many things concurrently
- Windows 7 any method longer than 40 ms must have asynchronous version
setTimeout(function() {
console.log('World!');
}, 2000);
console.log('Hello ');
Node and Async
- Node.js is Single Threaded
- JavaScript had to be asynchronous
- Netscape Navigator was released when there was no pre-emptive multi-tasking in modern OSs
- Use LibUV under the hood
- Error first Callbacks
- Promises
* https://www.codementor.io/theresamostert/understanding-non-blocking-i-o-in-javascript-cvmg1hp6l
Error First Callbacks
- Instead of returning a value, functions will expect parameter takes a another function
- The function or lambda will contain an error parameter, and a results parameter
- function query('Arg', function (err, data) {...})
Error first callbacks
function callFn(err, result) {
if (err) console.error(err);
console.log(result);
}
function makeDatabaseQuery(params, cb) {
// ...Do your magic
const result = magicIsCompleted();
if (error) {
cb(error, null);
} else {
cb(null, result);
}
}
makeDatabaseQuery(['12', false, 'Larry'], callFn);
Callback Hell
- JavaScript allows inline functions or lambda
- Developers can wind up having massive trees of callbacks inside one method
- Hard to read and unintuitive
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function (width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})
Promises
- A type of Monad
- Built in type in Node and JavaScript
- Can chain and nest Promises
- Handling functions with .then and .catch
- Avoids callback Hell, but can still be tricky
const promise = new Promise(function(resolve, reject) {
// do a thing, possibly async, then…
if (/* everything turned out fine */) {
resolve("Stuff worked!");
}
else {
reject(Error("It broke"));
}
});
promise.then(result => {
console.log(result);
}).catch(err => {
console.error(err);
});
const promise = new Promise(function(resolve, reject) {
resolve(1);
});
promise.then(function(val) {
console.log(val); // 1
return val + 2;
}).then(function(val) {
console.log(val); // 3
})
Async Await Keywords
- 'async/await' added Node and JavaScript in Node v8
- To make any function asynchronous, place 'async' keyword to the beginning of function
- Place 'await' keyword in front of asynchronous calls like promises instead of using '.then()' handler
- Allows JavaScript developers to write their code in a more synchronous way
- Also available in C#
- In Swift 5.5, iOS/iPadOS 15, MacOS 12
- Also in Rust
Async/Await behind the scenes
- Async tells the compiler to expect awaits on function
- Await proceeds Promises, but allow synchronous style syntax
- Compiler will divide functions into starting and callback functions
- If you have one 'await' keyword function will be divided into two functions
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: 'resolved'
}
asyncCall();
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
Top level await using type Module
Considerations
- Design your APIs to use Promises
- async functions and Promises are interchangeable
- Node process still Single-Threaded
- Making function async does not make it faster
Other Languages that feature Async/Await
- F#
- C#
- Rust
- Swift
open System
open System.IO
let printTotalFileBytes path =
async {
let! bytes = File.ReadAllBytesAsync(path) |> Async.AwaitTask
let fileName = Path.GetFileName(path)
printfn $"File {fileName} has %d{bytes.Length} bytes"
}
[<EntryPoint>]
let main argv =
printTotalFileBytes "path-to-file.txt"
|> Async.RunSynchronously
Console.Read() |> ignore
0
F#
private static async Task<int> DownloadDocsMainPageAsync()
{
Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: About to start downloading.");
var client = new HttpClient();
byte[] content = await client.GetByteArrayAsync("https://docs.microsoft.com/en-us/");
Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: Finished downloading.");
return content.Length;
}
C#
async fn example(min_len: usize) -> String {
let content = async_read_file("mycatdata.txt").await;
if content.len() < min_len {
content + &async_read_file("myfelinedata.txt").await
} else {
content
}
}
Rust
func processImageData1() async -> Image {
let dataResource = await loadWebResource("dataprofile.txt")
let imageResource = await loadWebResource("imagedata.dat")
let imageTmp = await decodeImage(dataResource, imageResource)
let imageResult = await dewarpAndCleanupImage(imageTmp)
return imageResult
}
Swift async/await
async let firstPhoto = downloadPhoto(named: photoNames[0])
async let secondPhoto = downloadPhoto(named: photoNames[1])
async let thirdPhoto = downloadPhoto(named: photoNames[2])
let photos = await [firstPhoto, secondPhoto, thirdPhoto]
show(photos)
Swyft Spawn multiple Threads
Demo
Questions?
Async/Await
By David Fekke
Async/Await
- 684