【JavaScript】异步解决方案发展历程

JavaScript 异步解决方案发展历程及获取异步方法中数据的几种方式

什么是异步?

当前一个任务被执行时,不会等待任务执行完成后就去执行下一个任务,等前一个任务执行完成后,将去执行其返回的回调函数,这就是异步操作,同步为阻塞模式,异步为非阻塞模式;可以理解为与现实生活中相反

JavaScript 中为什么需要异步?

首先我们知道 JavaScript 是单线程的(即使新增了 webworker,但是本质上 JS 还是单线程)。同步代码意味着什么呢?意味着有可能会阻塞,当我们有一个任务需要时间较长时,如果使用同步方式,那么就会阻塞之后的代码执行。而异步则不会,我们不会等待异步代码的之后,继续执行异步任务之后的代码。

异步解决方案发展历程:

回调函数 callback

被作为实参传入另一函数,并在该外部函数内被调用,用以来完成某些任务的函数。如 setTimeOutajax 请求,readFile

function greeting(name) {
  console.log('Hello,' + name)
}
function processUserInput(callback) {
  let name = 'ABing'
  callback(name)
}
processUserInput(greeting) // ABing

优点:解决了异步问题

缺点:回调地狱,多个回调函数嵌套的情况,使代码看起来十分混乱,不易于维护

Promise

PromiseES6 提出的异步编程的一种解决方案

Promise 对象有三种状态:

  • pending:初始状态,既不是成功,也不是失败
  • fulfilled:操作成功完成
  • rejected:操作失败

promise 的状态只能从 pending 变成 fulfilled,和 pending 变成 rejected,状态一旦改变,就不会再改变,且只有异步操作的结果才能改变 promise 的状态

function person(name) {
  return new Promise((resolve, reject) => {
    resolve(name)
  })
}
person('ABing').then(data => console.log(data)) // ABing

优点:解决了回调地狱的问题,将异步操作以同步操作的流程表达出来

缺点:无法取消 Promise;如果不设置回调函数,Promise 内部抛出一个错误,不会反映到外部。当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。当执行多个 Promise 时,一堆 then 看起来也很不友好

Generator

Generatores6 提出的另一种异步编程解决方案,需要在函数名之前加一个*号,函数内部使用 yield 语句。Generaotr 函数会返回一个遍历器,可以进行遍历操作执行每个中断点 yield

function* count() {
  yield 1
  yield 2
  return 3
}
let c = count()
console.log(c.next()) // { value: 1, done: false }
console.log(c.next()) // { value: 2, done: false }
console.log(c.next()) // { value: 3, done: true }
console.log(c.next()) // { value: undefined, done: true }

优点:没有了 Promise 的一堆 then(),异步操作更像同步操作,代码更加清晰

缺点:不能自动执行异步操作,需要写多个 next()方法,需要配合使用 Thunk 函数和 Co 模块才能做到自动执行

async/await

async 是 es2017 引入的异步操作解决方案,可以理解为 Generator 的语法糖,async 等同于 Generatorco 模块的封装,async 函数返回一个 Promise

async function Data() {
  return 'ABing'
}

async function getData() {
  console.log(await Data())
}
getData() // ABing

优点:内置执行器,比 Generator 操作更简单。async/await*/yield 语义更清晰。返回值是 Promise 对象,可以用 then 指定下一步操作。代码更整洁。可以捕获同步和异步的错误

缺点:频繁使用可能会导致网页阻塞,一致推荐的异步操作写法

获取异步方法中的数据的几种方式:

使用回调函数

function Data(callback) {
  setTimeout(function () {
    let name = 'ABing'
    callback(name)
  }, 1000)
}
Data(function (name) {
  console.log(name) // ABing
})

使用 Promise

let p = new Promise(function (resolve, reject) {
  setTimeout(function () {
    let name = 'ABing'
    resolve(name)
  }, 1000)
})
p.then(data => console.log(data)) // ABing

或者

function Data(resolve, reject) {
  setTimeout(function () {
    let name = 'ABing'
    resolve(name)
  }, 1000)
}
let p = new Promise(Data)
p.then(data => console.log(data))

使用 async 和 await

async function Data() {
  return 'ABing'
}

async function getData() {
  console.log(await Data())
}
getData() // ABing

总结

JS 的异步发展史,可以认为是从 callback -> promise -> generator -> async/awaitasync/await 使得异步代码看起来像同步代码,异步编程发展的目标就是让异步逻辑的代码看起来像同步一样

posted @ 2020-05-25 09:50  [ABing]  阅读(229)  评论(0编辑  收藏  举报