首先这里非常感谢慕课网蜗牛老湿,本文内容是基于老师讲解koa2实现原理的时候整理出来的,好吧,这里直接进入主题。

在我们平时进行前端开发的时候,经常需要用到异步函数,最常见的是发送网络请求,在发送网络请求之后,在回调函数中对请求结果再进行下一步操作,下面来模拟这个操作步骤:

/*
*   模拟网络请求的函数
*/
function request(callback) {let time = Math.random() * 1000                 //为了模拟每次请求的时长不同,这里每次等待随机时间0到1ssetTimeout(() => callback(), time)              //请求结束之后,调用回调函数
}request(function () {console.log(1)
})
request(function () {console.log(2)
})
request(function () {console.log(3)
})

接下来看结果:

可以看到,这里执行了3次,但是每次输出的顺序都不一致,按照我们想要的结果,是每次都是百分之百顺序执行1 2 3,如果要达到这种效果的话,就得这么写:

/*
*   模拟网络请求的函数
*/
function request(param, callback) {let time = Math.random() * 1000                 //为了模拟每次请求的时长不同,这里每次等待随机时间0到1ssetTimeout(() => callback(param, time), time)              //请求结束之后,调用回调函数
}request(1, function (p1, t1) {console.log(p1, t1)request(2, function (p2, t2) {console.log(p2, t2)request(3, function (p3, t3) {console.log(p3, t3)})})
})

可以看到,代码一下子变得难维护了很多,现在这里还没有什么逻辑,等每一个request里面加上几十行的逻辑代码,缺点一下子就显现出来了,但是结果却是是没错的:

这里先来对比一下两种做法:

  1. 第一种,是针对异步方法来说的,也就是说,三个请求之间没有什么关系,可以同时发起,最终等待时间取决于请求时间最长的请求;
  2. 第二种,是针对同步方法来说的,也就是说,每个请求之间是有依赖关系的,这里的话,request3得等request2请求完毕才能执行,request2要等request1请求完毕才能执行,请求时长为三个请求的总时长;

第一种做法,实际上使用场景非常少,如果不是特殊的业务逻辑,这种使用方式是不被允许的,因为三个请求并没有关系,所以这三个请求,在后台是可以合并为一个请求的,也就是说一次请求就可以完成任务,硬分三次请求的话会留下一些隐患。比如以后要将该功能暴露给外部系统调用,总不能让人家发送三次请求吧,日积月累,也会浪费服务器带宽流量。

第二种实际上是经常要用到的,根据第一个请求的请求结果,处理业务逻辑,然后判断是否需要进行下一步请求。

好在es7给出了一个新的语法,让异步方法同步起来没有那么困难了,看代码(我这里跳过了Promise调用链的说明):

/*
*   模拟网络请求的函数
*/
function request(param) {return new Promise((resolve) => {let time = Math.random() * 1000                 //为了模拟每次请求的时长不同,这里每次等待随机时间0到1ssetTimeout(() => resolve({param, time}), time)              //请求结束之后,调用回调函数})
}async function start() {let {param: p1, time: t1} = await request(1)console.log(p1, t1)let {param: p2, time: t2} = await request(2)console.log(p2, t2)let {param: p3, time: t3} = await request(3)console.log(p3, t3)
}start()

不知道async/await的使用方法的同学,可以百度看看相关资料,网上已经说得很清楚,我这里就不再赘述了。结果:

可以看到结果仍然是正确的,但是里面的代码要比原来的要清爽很多,看起来也没有那么刺眼了……
接下来是本文的重点了,看代码:

/*
*   模拟网络请求的函数
*/
function request(param) {return new Promise((resolve) => {let time = Math.random() * 1000                 //为了模拟每次请求的时长不同,这里每次等待随机时间0到1ssetTimeout(() => resolve({param, time}), time)              //请求结束之后,调用回调函数})
}/*
* 合并异步方法
*/
function compose(middlewares) {return function (...args) {function dispatch(i) {let fn = middlewares[i];if (!fn) {return Promise.resolve();}else {return Promise.resolve(fn(...args,function next() {return dispatch(i + 1)}))}}return dispatch(0);}
}let funcs = [async function (originalParam, next) {let {param: p1, time: t1} = await request(1)console.log(p1, t1, originalParam)next();},async function (originalParam, next) {let {param: p2, time: t2} = await request(2)console.log(p2, t2, originalParam)next();},async function (originalParam, next) {let {param: p3, time: t3} = await request(3)console.log(p3, t3, originalParam)next();},
]compose(funcs)('start')

结果:

可以看到结果仍然是正确的,而且我们已经把需要同步的方法统一起来,放在了funcs这个数组中,这个数组中所有的异步函数通过compose会生成一个函数,执行这个函数会依次执行funcs数组中的异步函数,每个异步函数中都可以拿到一个next函数参数,执行该函数,就会执行下一个异步函数,如果在某一次异步函数中发现数据不对,就不执行next,中断了异步函数的同步执行,这样管理起来,所有的异步函数操作起来就方便多了。

这里还实现了koa2中间件的功能,比如看下面代码(其他没变,只变了funcs数组):

let funcs = [async function (originalParam, next) {console.log('1 start')next();console.log('1 end')},async function (originalParam, next) {console.log('2 start')next();console.log('2 end')},async function (originalParam, next) {console.log('3 start')next();console.log('3 end')},
]

结果

通过这样的拦截操作,我们可以实现对任意对象任意函数进行拦截功能,详情说明,请见我的博客:基于koa2中间件原理实现拦截任意对象方法的调用

JavaScript异步函数同步方法相关推荐

  1. 细说JavaScript异步函数发展历程

    2019独角兽企业重金招聘Python工程师标准>>> < The Evolution of Asynchronous JavaScript >外文梳理了JavaScri ...

  2. async js 返回值_获取JavaScript异步函数的返回值

    今天研究一个小问题: 怎么拿到JavaScript异步函数的返回值? 1.错误尝试 当年未入行时,我的最初尝试: function getSomething() { var r = 0; setTim ...

  3. javascript --- 异步函数的顺序进行

    假设我们希望某一组异步函数能一次进行,在不使用的任何工具的情况下,可能会编写出类似下面的代码: funcs[0](function() {funcs[1](function() {funcs[2](o ...

  4. JavaScript 异步函数解析

    前言 在学习 JavaScript 的过程中,理解并灵活运用异步相关知识是一件不容易的事情,这体现在代码可读性.健壮性上,好在 ES6 出现后挽回了这一局面,我们不再需要编写可读性不高的回调嵌套,也不 ...

  5. JavaScript异步函数Promise①——Promise筑基

    期约是对尚不存在的一个替身.期约(promise)这个名字最早是由 Daniel Friedman和 David Wise在他们于 1976 年发表的论文"The Impact of App ...

  6. ES2017异步函数现已正式可用

    2019独角兽企业重金招聘Python工程师标准>>> ES2017标准已于2017年6月份正式定稿了,并广泛支持最新的特性:异步函数.如果你曾经被异步 JavaScript 的逻辑 ...

  7. ES2017 异步函数async/await

    ES2017标准已于2017年6月份正式定稿了,并广泛支持最新的特性:异步函数.如果你曾经被异步 JavaScript 的逻辑困扰,这么新函数正是为你设计的. 异步函数或多或少会让你编写一些顺序的 J ...

  8. JavaScript 异步编程--Generator函数、async、await

    JavaScript 异步编程–Generator函数 Generator(生成器)是ES6标准引入的新的数据类型,其最大的特点就是可以交出函数的执行的控制权,即:通过yield关键字标明需要暂停的语 ...

  9. JavaScript异步编程【上】 -- 同步和异步、事件循环(EventLoop)、微任务和宏任务、回调函数

    文章内容输出来源:拉勾教育 大前端高薪训练营 前言 在我们学习JavaScript中,我们知道,JavaScript的执行环境是单线程的.所谓单线程是指一次只能完成一个任务,如果有多个任务,就必须排队 ...

最新文章

  1. 中文文本挖掘预处理流程总结
  2. Epicor 安装Enterprise search
  3. 查看MySQL句柄_mysql查询语句-handler
  4. php 通知客户端,PHP+SSE服务器向客户端推送消息
  5. firedebug调试Jquery
  6. android webview javascript不执行,WebView中的JavaScript为什么不执行?
  7. 无法建立跟远程计算机的连接,彻底解决win8、win10系统宽带拨号出现“错误720:不能建立到远程计算机的连接”的问题-网络教程与技术 -亦是美网络...
  8. linux media v4l2,Linux kernel drivers/media/v4l2-core/videobuf2-v4l2.c拒绝服务漏洞(CVE-2016-4568)...
  9. CCF NOI1145 数字金字塔【DP】
  10. 2018.09.02 bzoj1025: [SCOI2009]游戏(计数dp+线筛预处理)
  11. Fundebug后端Java异常监控插件更新至0.3.1,修复Maven下载失败的问题
  12. 一个简单的python小游戏
  13. 贴片电阻的功率与封装对照表
  14. 如何用纯 CSS 创作一个永动的牛顿摆
  15. NO.013-2018.02.18《鹊桥仙·纤云弄巧》宋代:秦观
  16. 5gh掌上云计算认证不通过_华为云计算认证含金量怎么样?
  17. laravel5.4新特性
  18. 林达华博士对数学的见解
  19. jsp小区物业停车管理系统毕业设计
  20. TLD和eTLD的区别

热门文章

  1. 大牛首聚DTCC:分享数据治理应用案例
  2. mysql oracle驱动安装步骤_oracle服务器 驱动安装步骤
  3. __attribute__((weak))介绍以及用法
  4. opencv基本操作一(读取、处理、保存图片)
  5. Flashlight
  6. 快鲸智慧楼宇系统:助力商办楼宇快速实现智慧化、数字化运营
  7. python两列相乘_Python代码将两列相乘,然后用值创建新列
  8. Excel函数实现腾讯在线文档Excel会员功能——标记重复值
  9. idea取消屏幕中间的竖线
  10. linux(ubuntu16.04)系统下Matlab2015b软件下载与安装