JavaScript and TypeScript support various

Callbacks

window.setTimeout(function () {

}, 1000);
$.ajax('/api/user' + id, {
    method: 'GET',
    success: function(user: IUser) {

    },
    error: function(reason: any) {

    }
});
function getUser(id, success: (user: IUser) => void, error: (reason: any) => void)
    $.ajax('/api/user' + id, {
        method: 'GET',
        success:success,
        error: error
    });
}
function editUserPhone(id: string, phoneNumber: string, success: (result: boolean) => void, error: (reason: any) => void) {
    getUser(id, function (user) {
        if (user && user.id) {
            getPhone(user.id, function (phone) {
                if (phone && phone.id) {
                    phone.phoneNumber = phoneNumber;
                    updatePhone(phone.id, phone, function (result: boolean) {
                        if (result) {
                            success(result);
                        } else {
                            error('Unable to update phone');
                        }
                    }, function (reason: any) {
                        error(reason);
                    });
                } else {
                    error('No phone found');
                }
            },
            function (reason: any) {
                error(reason);
            });
        } else {
            error('No user found');
        }
    }, function (reason: any) {
        error(reason);
    });
}

Promises

Let's take a look at the Promise style code. Here, each asynchronous function returns a Promise object, instead of taking in callback parameters. This Promise provides access to the result of exactly one execution of the nested function. Callbacks that execute many times, such as window.setInterval, Array.prototype.forEach, Array.prototype.map, etc., are used different from Promises.

function editUserPhone(id: string, phoneNumber: string) {
    return getUser(id).then(function (user) {
        if (!user || !user.id) {
            throw 'No user found';
        }

        return getPhone(user.id).then(function (phone) {
            if (!phone || !phone.id) {
                throw 'No phone found';
            }

            phone.phoneNumber = phoneNumber;
            return updatePhone(phone.id, phone).then(function (result: boolean) {
                if (!result) {
                    throw 'Unable to update phone';
                }

                return result;
            });
        });
    });
}

Async/Await

Let's now take a look at the async and await symbols. If we mark a function as async, it implicitly returns a Promise object. This return type can be autogenerated by TypeScript, so a function that returns a boolean is now Promise<boolean>.

Once we have marked it as async, we gain access to the await symbol. We simply use await before executing any function that returns a Promise. Instead of having to write .then(function (result) { }), the result will be turned to the left of the statement. We can now write let result = await getValue();, and result will be populated with the data return from the asynchronous call.

async function editUserPhone(id: string, phoneNumber: string) {
    let user = await getUser(id);
    if (!user || !user.id) {
        throw 'No user found';
    }

    let phone = await getPhone(user.id);
    if (!phone || !phone.id) {
        throw 'No phone found';
    }

    phone.phoneNumber = phoneNumber;
    let result = await updatePhone(phone.id, phone);
    if (!result) {
        throw 'Unable to update phone';
    }

    return result;
}