资讯专栏INFORMATION COLUMN

js 异步编程

diabloneo / 356人阅读

摘要:总结这篇文章简单的介绍了一些常用的异步编程的方法,如果有错误或不严谨的地方,欢迎批评指正,如果喜欢,欢迎点赞收藏。

大家都知道js的执行环境是单线程的,如果没有异步编程,那么js的执行效率会非常低下,导致程序十分卡顿,一提到异步编程大家首先的想到的一定是回调函数,这也是最常用的异步编程的形式,但其实常用的还有Promise和Async函数,接下来就让我们一起学习这几种常用的异步编程方法。

回调函数

回调函数就是把任务的第二段多带带写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数,来看一个简单的例子:

function print(name, callback) {
  setTimeout(() => {
    console.log(name)
    if (callback) {
      callback()
    }
  }, 1000)
}
print("a", function () {
  print("b")
})

上面这个例子中将print("b")放在print("a")的回调函数中,这样就能按顺序依次打印a、b,但是回调函数有一个很明显的问题,就是当回调函数嵌套过深时,会导致代码混乱,不够清晰,这就是人们常说的对调地狱,来看下面这个例子:

function print(name, callback) {
  setTimeout(() => {
    console.log(name)
    if (callback) {
      callback()
    }
  }, 1000)
}
print("a", function () {
  print("b", function () {
    print("c", function () {
      print("d")
    })
  })
})

当我们想按顺序依次打印a、b、c、d时,代码就变成上面的样子,可以看到,我们的代码形成四层嵌套,如果还要加回调函数就要继续嵌套,这样嵌套会越写越深,越来越难以维护,此时我们就必须考虑用新的技术去改进,es6的Promise函数应运而生,接下来让我们看Promise函数是如何改进这个问题的。

Promise
function print(name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(name)
      resolve()
    }, 1000)
  })
}
print("a").then(() => {
  return print("b")
})
  .then(() => {
    return print("c")
  })
  .then(() => {
    return print("d")
  })

和之前用回调函数的形式相比,Promise函数写法更加清晰,由回调函数的嵌套调用变成了链式调用,但是Promise也有一个很严重的问题就是代码冗余,原来的任务被Promise包装了一下,不管什么操作都是放在then函数里面,导致代码的语以变差,有什么更好的解决办法呢?如果您对Promise函数还想有更深入的了解,可以去看阮一峰老师es6入门

Async

在正式使用异步函数之前,先简单的介绍一下它的用法,async通常与await一起使用,async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到触发的异步操作完成,再接着执行函数体后面的语句。做了简单的介绍后,接下来,我们来async函数是怎么对Promise调用优化的。看下面的例子:

function print(name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(name)
      resolve()
    }, 1000)
  })
}
async function test () {
  await print("a")
  await print("b")
  await print("c")
  await print("d")
}
test()

async函数来处理之前的问题,代码就是上面的这个例子中所展示的样子,是不是感觉代码瞬间清晰了,而且代码更加好理解了,再仔细思考一下使用async异步函数就很完美了吗?其实async异步函数也有其固有的问题,接下来我们就看看async异步函数还有什么问题需要解决。

错误捕获

异步函数第一个需要解决的问题就是错误捕获的问题,让我们看看一般情况下async异步函数是怎么做错误捕获的,来看一个例子:

function print(name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(name)
      resolve()
    }, 1000)
  })
}
async function test () {
  try {
    await print("a")
  } catch (err) {
    console.log(err)
  }
}
test()

当使用上述形式的try,catch进行错误捕获的时候,是不是觉得代码和使用Promise函数时一样啰嗦,那有没有好的解决办法呢?让我们来看另外一个例子:

function print(name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(name)
      resolve("a")
    }, 1000)
  })
}
async function test () {
  let [ err, result ] = await to(print("a"))
  if (err) throw err
  return result
}
test()

to.js:

function to(promise, errorExt) {
  return promise
    .then(function (data) { return [null, data]; })
    .catch(function (err) {
      if (errorExt) {
        Object.assign(err, errorExt);
      }
      return [err, undefined];
    });
}

export { to };
export default to;    

上述例子中,将async异步函数的错误处理封装到了一个to.js中,这里面其实只有一个简单方法,传入一个Promise对象,对Promise对象进行错误捕获返回值,用解构的形式获取返回值和错误,这样就不需要反复写try catche做错误捕获了。to.js是一个开源库

异步陷阱

什么是异步陷阱呢?在使用async异步函数的时候,多个异步操作是可以同时执行,但是有await命令变成了继发的形式了,即必须等待前一个执行完了后一个才能执行,还是之前的例子:

function print(name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(name)
      resolve()
    }, 1000)
  })
}
async function test () {
  await print("a")
  await print("b")
  await print("c")
  await print("d")
}
test()

假设await print("a")、await print("b")、await print("c")、await print("d")这四个操作并没有先后的逻辑关系,可以同时执行,那么按照上面的写法就会导致前一个执行完再执行下一个,整个执行过程中的等待时间会有4s,但是同时执行的等待时间就只有1s,这是在使用async异步函数会经常忽略的一个问题,那么怎么解决呢?介绍一个我经常使用的办法,看例子:

function print(name) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(name)
      resolve("a")
    }, 1000)
  })
}
async function test () {
  Promise.all([print("a"), print("b"), print("c"), print("d")])
}
test()

其实解决办法很简单就是通过Promise.all()方法,将所有异步操作作为参数数组传入,这样print("a")、print("b")、print("c")、print("d")这四个异步操作就可以并发执行了。

总结

这篇文章简单的介绍了一些常用的异步编程的方法,如果有错误或不严谨的地方,欢迎批评指正,如果喜欢,欢迎点赞收藏。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98835.html

相关文章

  • js学习之异步处理

    摘要:学习开发,无论是前端开发还是都避免不了要接触异步编程这个问题就和其它大多数以多线程同步为主的编程语言不同的主要设计是单线程异步模型。由于异步编程可以实现非阻塞的调用效果,引入异步编程自然就是顺理成章的事情了。 学习js开发,无论是前端开发还是node.js,都避免不了要接触异步编程这个问题,就和其它大多数以多线程同步为主的编程语言不同,js的主要设计是单线程异步模型。正因为js天生的与...

    VioletJack 评论0 收藏0
  • 【Node Hero】3. 理解异步编程

    摘要:异步编程在传统编程实践中,大多数操作都是同步发生的。中的异步编程异步是一种输入输出处理的形式,它允许在传输完成之前,其它处理能继续进行。 本文转载自:众成翻译译者:网络埋伏纪事链接:http://www.zcfy.cc/article/1759原文:https://blog.risingstack.com/node-hero-async-programming-in-node-js/ ...

    kevin 评论0 收藏0
  • nodejs异步编程详解

    摘要:四异步编程解决方案模式模式一定程度上缓解了嵌套回调的问题,只会处在未完成完成态失败态中的一种,只会从未完成转化为完成态或者失败态,不能逆转。 一、从一个简单的案例开始 fs.readdir(path.join(__dirname, ./index.js), (err, files) => { files.foreach((filename, index) => { ...

    inapt 评论0 收藏0
  • JavaScript 异步编程

    摘要:下面我将介绍的基本用法以及如何在异步编程中使用它们。在没有发布之前,作为异步编程主力军的回调函数一直被人诟病,其原因有太多比如回调地狱代码执行顺序难以追踪后期因代码变得十分复杂导致无法维护和更新等,而的出现在很大程度上改变了之前的窘境。 前言 自己着手准备写这篇文章的初衷是觉得如果想要更深入的理解 JS,异步编程则是必须要跨过的一道坎。由于这里面涉及到的东西很多也很广,在初学 JS 的...

    lordharrd 评论0 收藏0
  • [ JS 进阶 ] 异步编程 promise模式 的简单实现

    摘要:为了降低异步编程的复杂性,所以。难理解请参考的误区以及实践异步编程的模式异步编程的种方法 异步编程 javascript异步编程, web2.0时代比较热门的编程方式,我们平时码的时候也或多或少用到,最典型的就是异步ajax,发送异步请求,绑定回调函数,请求响应之后调用指定的回调函数,没有阻塞其他代码的执行。还有像setTimeout方法同样也是异步执行回调的方法。 如果对异步编程...

    svtter 评论0 收藏0

发表评论

0条评论

diabloneo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<