Cancelling a coroutine is "cooperative". The coroutine being canceled needs to take some steps to respond to the cancellation request, as we will see in upcoming lessons.

cancelAndJoin() cancels a coroutine and then blocks until that coroutine completes its cancellation work.

In this snippet, though, delay() cancels very quickly. As a result, the first coroutine will cancel very quickly, and so there is little additional delay introduced by using cancelAndJoin() instead of cancel(). But, if delay() were to wait for the full two seconds regardless of our cancellation request, then the second coroutine would take four total seconds to run: two seconds blocking on the first coroutine to complete cancellation, and two seconds for its own delay.

You can learn more about this in:
Run Edit