JavaScript默认是同步的,而且是单线程的。所以js代码无法创建新线程,不能并行执行。我们一起来ES中怎么编写异步执行代码。
编程语言中的异步特性
计算机在设计上是异步的。
异步意味着可以执行多任务。
在我们的计算机中,每个程序都运行在一个特定的时间段,然后它停止运行,让另一个程序继续执行。这个过程很快,以至于无法注意到,我们认为计算机同时运行许多程序,但这是一种错觉(除了在多处理器机器上)。
程序内部使用中断信号,这是一个发送到处理器的信号,以引起系统的注意。
我不会深入这个话题,但请记住,程序异步是很常见的。
通常情况,编程语言是同步的,它们提供了在语言库中管理异步的方法。 C,Java,C#,PHP,Go,Ruby,Swift,Python,默认情况下它们都是同步的。它们通过使用线程处理异步。
JavaScript
JavaScript默认是同步的,并且是单线程的。这意味着代码无法创建新线程,而且不会并行运行。
代码行是一个接一个地串行执行的,例如:
const a = 1const b = 2const c = a * bconsole.log(c)doSomething()
但JavaScript诞生于浏览器中,其主要工作在一开始就需要响应用户操作,如onClick,onMouseOver,onChange,onSubmit等。怎么用同步编程模型实现呢?
答案是在它的环境中。浏览器通过提供一组可以处理这种功能的API来提供一种方法。
最近,Node.js引入了一个非阻塞I / O环境,将这个概念扩展到文件访问,网络调用等。
回调
您无法知道用户何时要单击按钮,因此您要为click事件定义事件处理程序。此事件处理程序接受一个函数,该函数将在触发事件时调用:
const a = 1const b = 2const c = a * bconsole.log(c)doSomething()document.getElementById('button').addEventListener('click', () => { //item clicked})
这就是所谓的回调。
回调是一个简单的函数,它作为值传递给另一个函数,并且只在事件发生时执行。我们可以这样做,因为JavaScript有头等函数,可以分配给变量并传递给其他函数(称为高阶函数)。
在js代码中给window对象添加事件侦听器是很常见的,该window对象在页面ready时运行回调函数。
window.addEventListener('load', () => { //window loaded //do what you want})
回调能在任何地方都使用,而不仅仅在DOM事件中使用。一个常见的例子是使用定时器:
setTimeout(() => { // runs after 2 seconds}, 2000)
XHR请求也接受回调,在此示例中,状态改变时执行回调函数:
const xhr = new XMLHttpRequest()xhr.onreadystatechange = () => { if (xhr.readyState === 4) { xhr.status === 200 ? console.log(xhr.responseText) : console.error('error')} } xhr.open('GET', 'https://yoursite.com')xhr.send()d
处理回调中的错误
你如何处理回调错误?一个非常常见的策略是使用Node.js采用的:回调函数中的第一个参数是err对象。
如果没有错误,则该对象为null。如果有错误,则包含错误的描述和其他信息。
fs.readFile('/file.json', (err, data) => { if (err !== null) { //handle error console.log(err) return } //no errors, process data console.log(data)})
关于回调的问题
对于简单的情况,回调简单有用!
但是回调会增加嵌套层级,当你有很多回调时,代码开始变得非常复杂:
window.addEventListener('load', () => { document.getElementById('button').addEventListener('click', () => { setTimeout(() => { items.forEach(item => { //your code here }) }, 2000) })})
这只是一个简单的4级代码,我见还过更多层级的嵌套,这维护起来很困难。我们如何解决这个问题?
回调的替代方案
从ES6开始,JavaScript引入了一些功能,不使用回调也可以处理异步:
- Promises (ES6)
- Async/Await (ES8)