不同于同步模式的执行方式,异步模式的API不会等待任务的结束才开始执行下一个任务。对于耗时操作,它都是开启过后就立即往后执行下一个任务。耗时任务的后续逻辑一般会通过回调函数的方式定义,在内部耗时任务完成以后就会自动执行这个回调函数。异步模式对Javascript非常重要,因为没有异步模式的话Javascript语言就无法同时处理大量的耗时操作。对于开发者而言,单线程模式下面的异步最大的难点就是代码执行的顺序混乱。
异步调用在JS中的实现过程,以及它的基本原理:首先加载整体代码到执行环境中,并在调用栈中压入一个匿名函数调用,然后依次执行每行代码。遇到同步代码会进行压栈-执行-弹栈这样的运行流程;遇到异步代码时也会先进行压栈,然后在内部API为这个异步操作开启一个倒计时器。这个倒计时器是单独工作的,并不会收到当前的JS线程影响。开启倒计时后,对这个异步程序来讲,它的调用已经完成了。它也会从执行栈中弹出并执行后面的任务,调用栈所有的任务执行完毕以后会被清空,这时事件循环Event Loop就会被启动进行工作。事件循环Event Loop它其实只做一件事,就是负责监听调用栈 Call Stack 和消息队列 Queue。一旦调用栈中所有的任务都结束了,事件循环就会从消息队列中取出第一个回调函数,然后压入到调用栈中。我们在执行调用栈的同时,倒计时器也在同时执行并在倒计时结束后进入消息队列。一旦消息队列发生了变化,事件循环就会监听到。然后就会把消息队列当中的任务,从前到后压入调用栈中执行。对于调用栈来说此时等于开启了新一轮的调用,执行过程和原来一样。如果这个过程有遇到异步调用,它也是相同的情况。先会把它放入到API环境里面去单独执行,再往后就是按照这个流程执行。直到我们的调用栈和消息队列中都没有要执行的任务,整体的代码就结束了。如果说我们的调用栈是一个正在执行的工作表,消息队列就是一个待办的工作表。而JS执行引擎就是一个先去做完调用栈当中所有的任务,然后在通过事件循环从消息队列当中再取一个任务过来继续执行,以此类推整个过程,我们随时都可以往消息队列当中再去放入一些任务。这些任务在消息队列当中,会排队等待事件循环。
在JS当中JS线程在某一个时刻发起一个异步调用,然后它紧接着继续往后执行其他的任务,此时异步线程会单独去执行这个异步任务。然后在执行完这个任务过后,会将这个任务的回调放入到消息队列。JS主线程完成所有的任务后,会依次调用执行我们消息队列当中的任务。
总结:同步也好异步也好,不是指我们写代码的方式而是说我们运行环境提供的API是以同步或异步模式的方式工作。对于同步模式的API它的特点就是这个任务执行完代码才会继续往下走,对于异步模式的API,它就是下达这个任务开启的指令,就会继续往下执行,代码不会在这一行等待任务结束。