深入浅出 JS 异步处理技术方案
为什么要异步 “当我们在星巴克买咖啡时,假设有 100 个人在排队,也许咖啡的下单只要 10 秒,但是咖啡的制作到客人领取咖啡要 1000 秒。如果在同步的场景下,第一个客人下单到领取完咖啡要 1010 秒才能轮到下一个客人,这在效率(某些场景)上来说会比较低下。 如果我们异步处理这个流程,客人下单 10 秒拿到凭证,客人就可以去做别的事情,并且 10 秒后下一个客人可以继续下单,并不阻碍流程。反而可以通过凭证,让客人拿到自己的咖啡,也许时间上并不是第一个下单的客人先拿到。
在网页的世界里也是同样的道理,不妨我们看看在执行 JS 代码的主线程里,如果遇到了 AJAX 请求,用户事件等,如果不采用异步的方案,你会一直等待,等待第一个耗时的处理完成才能接上下一个 JS 代码的执行,于是界面就卡住了。 也许有人会想,既然大家都说现在网页上性能损耗最大的属于 DOM 节点的操作,把这些搞成异步,行不行?其实这会带来一个不确定性问题:既 “成功” 的状态到底谁先来的问题。 可以想象一下,如果我们在操作 DOM,既给节点添加内容,也给节点删除,那么到底以谁为基准呢?考虑到复杂性,也就可见一斑了。 Event loop 虽然异步与 event loop 没有太直接的关系,准确的来讲 event loop 只是实现异步的一种机制。(了解为主) 还是以上面咖啡馆为例子,假定场景还是 100 人,这 100 人除了下单是与咖啡本身有关联之外,其余的时间,比如看书,玩游戏的等可以视为自己的执行逻辑。 如果用 event loop 来给它做一个简单的画像,那么它就像:在与咖啡店店员沟通下单视为主执行栈,咖啡的制作可以视为一个异步任务,添加到一个任务队列里,一直等带 100 个人都下单完成,然后开始读取任务队列中的异步任务,事件名就是下单凭证,如果有对应的 handler,那么就执行叫对应的客人来领取咖啡。 这个过程,是循环不断的。假设没有客人来下单的时候,也就是店员处于空闲时间(可能自己去搞点别的)。 传统的 Callback 假定一个 asyncFetchDataSource 函数用于获取远程数据源,可能有 20 秒。 function asyncFetchDataSource(cb){ (… 获取数据 , function(response){ typeof cb === “function”