什么是异步
JS 为何会有异步
JS 是单线程的语言,所谓“单线程”就是一根筋,对于拿到的程序,一行一行的执行,上面的执行为完成,就傻傻的等着。例如:
1 | let i, t = Date.now(); |
上面的程序花费 261ms 的时间执行完成,执行过程中就会有卡顿,其他的事儿就先撂一边不管了。
执行程序这样没有问题,但是对于 JS 最初使用的环境 ———— 浏览器客户端 ———— 就不一样了。因此在浏览器端运行的 js ,可能会有大量的网络请求,而一个网络资源啥时候返回,这个时间是不可预估的。这种情况也要傻傻的等着、卡顿着、啥都不做吗?———— 那肯定不行。
因此,JS 对于这种场景就设计了异步 ———— 即,发起一个网络请求,就先不管这边了,先干其他事儿,网络请求啥时候返回结果,到时候再说。这样就能保证一个网页的流程运行。
异步的实现原理
1 | let ajax = $.ajax({ |
上面代码中$.ajax()
需要传入两个参数进去,url
和success
,其中url
是请求的路由,success
是一个函数。这个函数传递过去不会立即执行,而是等着请求成功之后才能执行。对于这种传递过去不执行,等出来结果之后再执行的函数,叫做callback,即回调函数,所谓”回调函数”(callback),就是那些会被主线程挂起来的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。
再看一段更加能说明回调函数的 nodejs 代码。和上面代码基本一样,唯一区别就是:上面代码时网络请求,而下面代码时 IO 操作。
1 | let fs = require('fs') |
从上面两个 demo 看来,实现异步的最核心原理,就是将callback作为参数传递给异步执行函数,当有结果返回之后再触发 callback执行,就是如此简单!
常用的异步操作
- 网络请求,如
ajax
http.get
- IO 操作,如
readFile
readdir
- 定时函数,如
setTimeout
setInterval
事件绑定是不是也是异步操作?
异步和 event-loop
JavaScript 运行机制详解:再谈Event Loop
事件绑定算不算异步?
事件绑定和异步操作的实现机制是一样的,那么事件绑定是不是就是异步操作呢?(声明一下,这里说的事件绑定是如下代码的形式)
1 | $btn.on('click', function (e) { |
相同
从技术实现以及书写方法上来讲,他们是一样的。例如事件绑定和 IO 操作的写法基本相同。
1 | $btn.on('click', function (e) { |
最终执行的方式也基本一样,都会被放在 call-stack 中通过 event-loop 来调用。
不同
第一,event-loop 执行时,调用的源不一样。异步操作是系统自动调用,无论是setTimeout
时间到了还是$.ajax
请求返回了,系统会自动调用。而事件绑定就需要用户手动触发
第二,从设计上来将,事件绑定有着明显的“订阅-发布”的设计模式,而异步操作却没有。
其实,事件绑定在 js 中扮演着非常重要的角色,各个地方都会用到事件绑定的形式。例如 web 页面监控鼠标、键盘,以及 nodejs 中的 EventEmitter
应用非常广泛(特别是涉及到数据流时)。事件绑定被应用到非常广泛,却没有发生像异步操作带来的程序逻辑问题。