What is a callback?

A callback is a pattern that is used to retrieve the results of an asynchronous task. This approach assumes that we pass a reference to a function that should be invoked when an asynchronous operation is done. 

By synchronous operations, we mean that the tasks are executed one after another. The asynchronous approach assumes that several tasks can be performed in parallel. 

The loadImage function in the following example code uses a callback to return the result:

fun loadImage(callback: (Image) -> Unit) {
executor.submit {
Thread.sleep(3000)
callback(Image())
}
}

The preceding code snippet shows the simplest example of how to create an asynchronous function that returns the results using the callback. In our case, the callback is a lambda that takes an instance of the Image class and returns Unit. The following diagram shows how this sequence works:

This function can be used as follows:

fun main(args: Array<String>) {
loadImage { image ->
showImage(image)
}
}

The preceding snippet shows that it is easy to use a callback to deal with asynchronous code. We just implement and pass a lambda that is invoked when an image is ready.

The following diagram shows how to implement this approach:

Let's imagine that we are requesting a list of users from the server. After that, we send another request to get detailed information about a user, and then, we load an avatar. In code, this may look as follows:

fun loadListOfFriends(callback: (List<ShortUser>) -> Unit) {
executor.submit {
Thread.sleep(3000)
callback(listOf(ShortUser(0), ShortUser(1)))
}
}

The loadListOfFriends function takes a lambda that takes a list of instances of the ShortUser class, as follows:

fun loadUserDetails(id: Int, callback: (User) -> Unit) {
executor.submit {
Thread.sleep(3000)
callback(User(id, "avatar"))
}
}

The loadUserDetails function takes a lambda and an identifier of a user, as follows:

fun loadImage(avatar: String, callback: (Image) -> Unit) {
executor.submit {
Thread.sleep(3000)
callback(Image())
}
}

The loadImage function takes a path to the avatar and lambda. The following example code demonstrates the most common problem that occurs when we use an approach with callbacks. We encounter the problem of code complexity and readability when concurrent tasks have to pass data to each other:

fun main(args: Array<String>) {
loadListOfFriends {users ->
loadUserDetails(users.first().id) {user ->
loadImage(user.avatar) {image ->
showImage(image)
}
}
}
}

The preceding snippet demonstrates what callback hell is. We have a lot of nested functions, and it is hard to maintain this code.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.131.10