Asynchronous Programming & Promise

Junghoo Cho

cho@cs.ucla.edu

Traditional Programming

Multi-Threading

Single-Threaded JS Engine

Asynchronous API

Synchronous vs Asynchronous

Synchronous Asynchronous
user = db.find({userid: id}); db.find({userid: id}, callback);
  • Wait until when everything is ready
  • Return immediately, callback when ready
  • Next line in the code has the required object
    • We can do what we logically need to do in the next line
  • Next line in the code does not have required object
    • We cannot do what we logically need to do in the next line
  • All logical sequence of actions in one function
  • Actions are spread across multiple callback functions

Callback Hell

function sendPicture(id) {
    db.find({userid: id}, callback1);
}
function callback1(err, user) {
    fs.readFile(user.picFile, callback2);
}
function callback2(err, picture) {
    socket.write(picture, callback3);
}
function callback3() {
    console.log("done!");
}

Nested Callback Function

function sendPicture(id) {
    db.find({userid: id}, (err, user) => {
        fs.readFile(user.picFile, (err, picture) => {
            socket.write(picture, () => {
                console.log("done!");
            })
        })
    })
}

Promise (ECMAScript 2015)

let prom = db.find({userid: id});
prom.then(fulfillCallback[, rejectCallback]);

Promise Chain

function sendPicture(id) {
    let prom1 = db.find({userid: id}); 
    let prom2 = prom1.then(user => fs.readFile(user.picFile));
    let prom3 = prom2.then(picture => socket.write(picture));
    let prom4 = prom3.then(() => console.log("done!"));
}

Details on Settling Promise

let prom1 = db.find({userid: id});
let prom2 = prom1.then(fulCB1, rejCB1);
let prom3 = prom2.then(fulCB2, rejCB2);

Promise Chain: Rejection Forwarding

function sendPicture(id) {
    db.find({userid: id})
    .then(user => fs.readFile(user.picFile))
    .then(picture => socket.write(picture))
    .then(() => console.log("done!"))
    .catch(errorHandler);
}

Error Handling in Promise Callback

Guarantees of Promise

“Promisified” Asynchronous API

Creating a Promise

async/await (ECMAScript 2017)

async Function

async function sendPicture(id) {
    ...
    if (cond) {
        return val;
    } else {
        throw new Error("Error!");
    }
}

await Keyword

user = await db.find({userid: id});

async/await

async function sendPicture(id) {
    try {
        user = await db.find({userid: id});
        picture = await fs.readFile(user.picFile);
        await socket.write(picture);
        console.log("done!");
    } catch (e) {
        throw new Error("Cannot send the picture!");
    }
}

await in Top Block

Parallel await

function doubleAfter2Seconds(x) {
    return new Promise((resolve, reject) => setTimeout(resolve, 2000, x*2)); 
}

async function addAsync(x) {
    return await doubleAfter2Seconds(x)
         + await doubleAfter2Seconds(x)
         + await doubleAfter2Seconds(x);
}

addAsync(10).then(v => console.log(v));
async function addAsync(x) {
    const a = doubleAfter2Seconds(x);
    const b = doubleAfter2Seconds(x);
    const c = doubleAfter2Seconds(x);
    return await a + await b + await c;
}

addAsync(10).then(v => console.log(v));

What We Learned

References