美文网首页让前端飞
几种处理JavaScript异步操作的办法

几种处理JavaScript异步操作的办法

作者: 强哥科技兴 | 来源:发表于2019-04-12 15:56 被阅读0次

引言

js的异步操作,已经是一个老生常谈的话题,关于这个话题的文章随便google一下都可以看到一大堆。那么为什么我还要写这篇东西呢?在最近的工作中,为了编写一套相对比较复杂的插件,需要处理各种各样的异步操作。但是为了体积和兼容性,不打算引入任何的pollyfill,甚至连babel也不允许使用,这也意味着只能以es5的方式去处理。使用回调的方式对于解耦非常不利,于是找了别的方法去处理这个问题。问题是处理完了,却也引发了自己的一些思考:处理js的异步操作,都有一些什么方法呢?

1. 回调函数

传说中的“callback hell”就是来自回调函数。而回调函数也是最基础最常用的处理js异步操作的办法。我们来看一个简单的例子:

首先定义三个函数:

functionfn1() {

console.log('Function 1')

}

functionfn2() {

setTimeout(() => {

console.log('Function 2')

}, 500)

}

functionfn3() {

console.log('Function 3')

}

其中fn2可以视作一个延迟了500毫秒执行的异步函数。现在我希望可以依次执行fn1,fn2,fn3。为了保证fn3在最后执行,我们可以把它作为fn2的回调函数:

functionfn2(f) {

setTimeout(() => {

console.log('Function 2')

f()

}, 500)

}

fn2(fn3)

可以看到,fn2和fn3完全耦合在一起,如果有多个类似的函数,很有可能会出现fn1(fn2(fn3(fn4(...))))这样的情况。回调地狱的坏处我就不赘述了,相信各位读者一定有自己的体会。

2. 事件发布/订阅

发布/订阅模式也是诸多设计模式当中的一种,恰好这种方式可以在es5下相当优雅地处理异步操作。什么是发布/订阅呢?以上一节的例子来说,fn1,fn2,fn3都可以视作一个事件的发布者,只要执行它,就会发布一个事件。这个时候,我们可以通过一个事件的订阅者去批量订阅并处理这些

顺便给大家推荐一个裙,它的前面是 537,中间是631,最后就是 707。想要学习前端的小伙伴可以加入我们一起学习,互相帮助。群里每天晚上都有大神免费直播上课,如果不是想学习的小伙伴就不要加啦。

classAsyncFunArr{

constructor (...arr) {

this.funcArr = [...arr]

}

next() {

const fn = this.funcArr.shift()

if (typeof fn === 'function') fn()

}

run() {

this.next()

}

}

constasyncFunArr=newAsyncFunArr(fn1,fn2,fn3)

然后在fn1,fn2,fn3内调用其next()方法:

functionfn1() {

console.log('Function 1')

asyncFunArr.next()

}

functionfn2() {

setTimeout(() => {

console.log('Function 2')

asyncFunArr.next()

}, 500)

}

functionfn3() {

console.log('Function 3')

asyncFunArr.next()

}

//output=>

//Function1

//Function2

//Function3

可以看到,函数的处理顺序等于传入AsyncFunArr的参数顺序。AsyncFunArr在内部维护一个数组,每一次调用next()方法都会按顺序推出数组所保存的一个对象并执行,这也是我在实际的工作中比较常用的方法

3. Promise

使用Promise的方式,就不需要额外地编写一个消息订阅者函数了,只需要异步函数返回一个Promise即可。且看例子:

functionfn1() {

console.log('Function 1')

}

functionfn2() {

return new Promise((resolve, reject) => {

setTimeout(() => {

console.log('Function 2')

resolve()

}, 500)

})

}

functionfn3() {

console.log('Function 3')

}

同样的,我们定义了三个函数,其中fn2是一个返回Promise的异步函数,现在我们希望按顺序执行它们,只需要按以下方式即可:

fn1()

fn2().then(() => { fn3() })

//output=>

//Function1

//Function2

//Function3

使用Promise与回调有两个最大的不同,第一个是fn2与fn3得以解耦;第二是把函数嵌套改为了链式调用,无论从语义还是写法上都对开发者更加友好。

顺便给大家推荐一个裙,它的前面是 537,中间是631,最后就是 707。想要学习前端的小伙伴可以加入我们一起学习,互相帮助。群里每天晚上都有大神免费直播上课,如果不是想学习的小伙伴就不要加啦。

4. generator

如果说Promise的使用能够化回调为链式,那么generator的办法则可以消灭那一大堆的Promise特征方法,比如一大堆的then()。

functionfn1() {

console.log('Function 1')

}

functionfn2() {

setTimeout(() => {

console.log('Function 2')

af.next()

}, 500)

}

functionfn3() {

console.log('Function 3')

}

function*asyncFunArr(...fn) {

fn[0]()

yield fn[1]()

fn[2]()

}

constaf=asyncFunArr(fn1,fn2,fn3)

af.next()

//output=>

//Function1

//Function2

//Function3

在这个例子中,generator函数asyncFunArr()接受一个待执行函数列表fn,异步函数将会通过yield来执行。在异步函数内,通过af.next()激活generator函数的下一步操作。

这么粗略的看起来,其实和发布/订阅模式非常相似,都是通过在异步函数内部主动调用方法,告诉订阅者去执行下一步操作。但是这种方式还是不够优雅,比如说如果有多个异步函数,那么这个generator函数肯定得改写,而且在语义化的程度来说也有一点不太直观。

5. 优雅的async/await

使用最新版本的Node已经可以原生支持async/await写法了,通过各种pollyfill也能在旧的浏览器使用。那么为什么说async/await方法是最优雅的呢?且看代码:

functionfn1() {

console.log('Function 1')

}

functionfn2() {

return new Promise((resolve, reject) => {

setTimeout(() => {

console.log('Function 2')

resolve()

}, 500)

})

}

functionfn3() {

console.log('Function 3')

}

asyncfunctionasyncFunArr() {

fn1()

await fn2()

fn3()

}

asyncFunArr()

//output=>

//Function1

//Function2

//Function3

有没有发现,在定义异步函数fn2的时候,其内容和前文使用Promise的时候一模一样?再看执行函数asyncFunArr(),其执行的方式和使用generator的时候也非常类似。

异步的操作都返回Promise,需要顺序执行时只需要await相应的函数即可,这种方式在语义化方面非常友好,对于代码的维护也很简单——只需要返回Promise并await它就好,无需像generator那般需要自己去维护内部yield的执行。

相关文章

  • 几种处理JavaScript异步操作的办法

    引言 js的异步操作,已经是一个老生常谈的话题,关于这个话题的文章随便google一下都可以看到一大堆。那么为什么...

  • 几种处理JavaScript异步操作的办法

    引言 js的异步操作,已经是一个老生常谈的话题,关于这个话题的文章随便google一下都可以看到一大堆。那么为什么...

  • js任务管理和promise

    任务管理 JavaScript是单线程。JavaScript在处理异步操作时,利用的是事件循环机制。 主线程中的任...

  • javascript异步流程处理几种方式

    前言JavaScript 提倡书写异步方法, 这样可以更好地利用事件队列机制, 来高效的无阻塞的运行应用。但这容易...

  • ES6 之 Promise

    Promise是JavaScript异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步...

  • 异步处理async和await

    异步操作的几种手法 : 1. 回调函数2. 事件的方法3. generator 处理将 异步代码写成同步的方式 4...

  • Promise--异步的解决方案

    Promise 对象是 JavaScript 的异步操作解决方案,为异步操作提供统一接口,使得异步操作具备同步操作...

  • ES6(7)之Async和await

    先谈JavaScript的异步处理 JavaScript是一门单线程的编程语言,如果不设计异步处理的机制,很容易因...

  • 异步处理举例

    类比Java Web中的Servlet异步处理类比JavaScript中的Ajax异步处理类比WebSocket中...

  • 小程序中异步处理的几种方式对比

    异步处理方式 1.异步处理的几种方式 纯粹的异步回调函数callback promise方法 (async,awa...

网友评论

    本文标题:几种处理JavaScript异步操作的办法

    本文链接:https://www.haomeiwen.com/subject/nricwqtx.html