fangchaolong
文章57
标签24
分类10

(滴滴、挖财、微医、海康)JS 异步解决 方案的发展历程以及优缺点

JS 异步解决方案的发展历程以及优缺点:回调函数、Promise、Generator、Async/await

回调函数

优点:解决了同步的问题(只要有一个任务耗时很长,后面的任务都必须排队 等着,会拖延整个程序的执行。)
缺点:回调地狱,不能用 try catch 捕获错误,不能 return;(多个回调函数嵌套的时候会造成回调函数地狱,上下两层的回调函数间的代码耦 合度太高,不利于代码的可维护。不能用 try catch 捕获错误,不能 return)

ajax('XXX1', () => {
    // callback 函数体ajax('XXX2', () => {
        // callback 函数体ajax('XXX3', () => {
            // callback 函数体
        })
    })
})
回调地狱的根本问题在于:
缺乏顺序性:回调地狱导致的调试困难,和大脑的思维方式不符
嵌套函数存在耦合性,一旦有所改动,就会牵一发而动全身,即(控制反转)
嵌套函数过多的多话,很难处理错误

Promise

优点:解决了回调地狱的问题;

ajax('XXX1')
  .then(res => {
      // 操作逻辑returnajax('XXX2')
  }).then(res => {
      // 操作逻辑returnajax('XXX3')
  }).then(res => {
      // 操作逻辑
  }).catch(err => {
      // 错误处理
  })

缺点:无法取消 Promise,错误需要通过回调函数来捕

Generator

特点:可以控制函数的执行。(它可以在遇到异步函数执行的时候,将函数执行权转移出去,当异步函数执行完毕时再将执行权 给转移回来。因此在 generator 内部对于异步操作的方式,可以以 同步的顺序来书写。使用这种方式需要考虑的问题是何时将函数的控 制权转移回来,因此需要有一个自动执行 generator 的机制,比如 说 co 模块等方式来实现 generator 的自动执行。)

function* getResult() {
    yield new Promise((resolve, reject)=>{
        setTimeout(() => {
            resolve(1)
            console.log(1);
        }, 1000);
    })
    yield new Promise((resolve, reject)=>{
        setTimeout(() => {
            resolve(2)
            console.log(2);
        }, 500);
    })
    yield new Promise((resolve, reject)=>{
        setTimeout(() => {
            resolve(3)
            console.log(3);
        }, 100);
    })
}
const gen = getResult()
// gen.next() = {value: yield 返回的数据, done: 迭代器是否走完}
// gen.next().value 就是每一次 yield 之后返回的 Promise
// 递归封装
function co(g) {
    const newObj = g.next()
    // 递归停止条件: 当迭代器到最后一个yield
    if (newObj.done) {
        return
    }
    nextObj.value.then(()=>{
        co(g)
    })
}
co(gen)

Async/Await

原理:函数是 generator 和 promise 实现的 一个自动执行的语法糖,它内部自带执行器,当函数内部执行到一个 await 语句的时候,如果语句返回一个 promise 对象,那么函数将 会等待 promise 对象的状态变为 resolve 后再继续向下执行。因此 可以将异步逻辑,转化为同步的顺序来书写,并且这个函数可以自动 执行。

优点:代码清晰,不用像 Promise 写一大堆 then 链,处理了回调地狱的问题;
缺点:await 将异步代码改造成同步代码,如果多个异步操作没有依赖性而使用 await 会导致性能上的降低

async functiontest() {
  // 以下代码没有依赖性的话,完全可以使用 Promise.all 的方式// 如果有依赖性的话,其实就是解决回调地狱的例子了
  await fetch('XXX1')
  await fetch('XXX2')
  await fetch('XXX3')
}

let a = 0
let b = async () => {
  a = a + await 10
  console.log('2', a) // -> '2' 10
}
b()
a++
console.log('1', a) // -> '1' 1

无以生计,卖文苟延

微信
支付宝