标签 JavaScript 下的文章

本文通过分析一个小案例帮大家从一个侧面理解JavaScript的异步执行机制,从而可以在实践中避免类似的尴尬。

小背景

我们都知道,alert这种内置弹框会阻塞后续代码执行:

之所以如此,就是因为JavaScript代码在浏览器中是单线程执行的。换句话说,浏览器中只有一个主线程负责运行所有JavaScript代码(不考虑Web Worker)。

提到浏览器中的JavaScript,基本上只有三个来源:

  • BOM API的代码,让我们可以操作并利用浏览器提供的能力
  • DOM API的代码,让我们可以操作网页内容
  • 我们自己写的ECMAScript代码

这没什么。我们也知道,setTimeout用于“定时”执行代码,比如这样可以定时在3秒钟之后执行一段代码(函数):

setTimeout(delayCode, 3000)

- 阅读剩余部分 -

ES7(ECMAScript 2016)推出了Async函数(async/await),实现了以顺序、同步代码的编写方式来控制异步流程,彻底解决了困扰JavaScript开发者的“回调地狱”问题。比如,之前需要嵌套回调的异步逻辑:

const result = [];
// pseudo-code, ajax stand for an asynchronous request
ajax('url1', function(err, data){
    if(err) {...}
    result.push(data)
    ajax('url2', function(err, data){
        if(err) {...}
        result.push(data)
    })
})
console.log(result)

现在可以写成如下同步代码的样式了:

async function example() {
  const r1 = await new Promise(resolve =>
    setTimeout(resolve, 500, 'slowest')
  )
  const r2 = await new Promise(resolve =>
    setTimeout(resolve, 200, 'slow')
  )
  return [r1, r2]
}

example().then(result => console.log(result))
// ['slowest', 'slow']

Async函数需要在function前面添加async关键字,同时内部以await关键字来“阻塞”异步操作,直到异步操作返回结果,然后再继续执行。在没有Async函数以前,我们无法想象下面的异步代码可以直接拿到结果:

const r1 = ajax('url')
console.log(r1)
// undefined

这当然是不可能的,异步函数的结果只能在回调里拿到。可以说,Async函数是JavaScript程序员在探索如何高效异步编程过程中踩“坑”之后的努力“自救”获得的成果——不是“糖果”。然而,读者小哥哥小姐姐可能有所不知,Async函数实际上是一个语法糖(果然是“糖果”吗?),它的背后是ES6(ECMAScript 2015)中推出的Promise、Iterator和Generator,我们简称“PIG”。本文就带各位好好品尝品尝这块语法糖,感受一个PIG是如何成就Async函数的。

- 阅读剩余部分 -