导言:
我们都知道 JS 是单线程的,这也正是异步编程对于 JS 很重要的原因,因为它无法忍受耗时太长的操作。正因如此有一系列的实现异步的方法。
方法一 setTimeout
常用于:定时器,动画效果
用法:setTimeout(func|code,delay)
缺点:
setTimeout 的主要问题在于,它并非那么精确。譬如通过 setTimeout() 设定一个任务在 10 毫秒后执行,但是在 9 毫秒之后,有一个任务占用了 5 毫秒的 CPU 时间片,再次轮到定时器执行时,时间就已经过期 4 毫秒
方法二 事件监听
任务的执行不取决于代码的顺序,而取决于某个事件是否发生
用法:f1.on('done',f2);
优点:比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合",有利于实现模块化;
缺点:整个程序都要变成事件驱动型,运行流程会变得很不清晰;
方法三 回调函数
什么是回调函数?
JavaScript语言对异步编程的实现,就是回调函数。所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数;
误区:
回调函数是实现 JS 异步的一种方法,并不是说回调函数就是异步的。
只是我们用的大多数回调函数都是用于异步
异步的定义:
在javascript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。如果没有名称(函数表达式),就叫做匿名回调函数。
回调函数的缺点:(想想,如果再嵌套多几层,代码会变得难以理解,俗称"回调函数噩梦(callback hell)");
回调函数本身并没有问题,它的问题出现在多个回调函数嵌套。
假定读取A文件之后,从A文件中获取B文件名,再读取B文件,
方法四 Promise对象
Promise原本只是社区提出的一个构想,一些外部函数库率先实现了这个功能。ES6将其写入语言标准,因此目前 JavaScript 语言原生支持 Promise 对象,假设要依次读取多个文件,如果用普通的回调函数,就会出现多重嵌套。代码不是纵向发展,而是横向发展;
Promise的优缺点:
优点:Promise 的写法是回调函数的改进,使用then方法以后,异步任务的两段执行看得更清楚了。then将原来异步函数的嵌套关系转变为链式步骤;
缺点:Promise 的最大问题是代码冗余,原来的任务被Promise包装了一下,不管什么操作,一眼看去都是一堆 then,原来的语义变得很不清楚;
所以,ES6在把 Promise 纳入标准的同时,也提供了另一种实现 => Generator 函数