我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何深入探析koa中的异步回调处理

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何深入探析koa中的异步回调处理

本篇文章给大家分享的是有关如何深入探析koa中的异步回调处理,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

1. 回调金字塔及理想中的解决方案

我们都知道javascript是一门单线程异步非阻塞语言。异步非阻塞当然是它的一个优点,但大量的异步操作必然涉及大量的回调函数,特别是当异步嵌套的时候,就会出现回调金字塔的问题,使得代码的可读性非常差。比如下面一个例子:

var fs = require('fs');  fs.readFile('./file1', function(err, data) {   console.log(data.toString());   fs.readFile('./file2', function(err, data) {     console.log(data.toString());   }) })

这个例子是先后读取两个文件内容并打印,其中file2的读取必须在file1读取结束之后再进行,因此其操作必须要在file1读取的回调函数中执行。这是一个典型的回调嵌套,并且只有两层而已,在实际编程中,我们可能会遇到更多层的嵌套,这样的代码写法无疑是不够优雅的。

在我们想象中,比较优雅的一种写法应该是看似同步实则异步的写法,类似下面这样:

var data; data = readFile('./file1'); //下面的代码是***个readFile执行完毕之后的回调部分 console.log(data.toString()); //下面的代码是第二个readFile的回调 data = readFile('./file2'); console.log(data.toString());

这样的写法,就完全避免回调地狱。事实上,koa就让我们可以使用这样的写法来写异步回调函数:

var koa = require('koa'); var app = koa(); var request=require('some module');  app.use(function*() {   var data = yield request('http://www.baidu.com');   //以下是异步回调部分   this.body = data.toString(); })  app.listen(3000);

那么,究竟是什么让koa有这么神奇的魔力呢?

2. generator配合promise实现异步回调同步写法

关键的一点,其实前一篇也提到了,就是generator具有类似"打断点"这样的效果。当遇到yield的时候,就会暂停,将控制权交给yield后面的函数,当下次返回的时候,再继续执行。

而在上面的那个koa例子中,yield后面的可不是任何对象都可以哦!必须是特定类型。在co函数中,可以支持promise, thunk函数等。

今天的文章中,我们就以promise为例来进行分析,看看如何使用generator和promise配合,实现异步同步化。

依旧以***个读取文件例子来分析。首先,我们需要将读文件的函数进行改造,将其封装成为一个promise对象:

var fs = require('fs');  var readFile = function(fileName) {   return new Promise(function(resolve, reject) {     fs.readFile(fileName, function(err, data) {       if (err) {         reject(err);       } else {         resolve(data);       }     })   }) }  //下面是readFile使用的示例 var tmp = readFile('./file1'); tmp.then(function(data) {   console.log(data.toString()); })

关于promise的使用,如果不熟悉的可以去看看es6中的语法。(近期我也会写一篇文章来教大家如何用es5的语法来自己实现一个具备基本功能的promise对象,敬请期待呦^_^)

简单来讲,promise可以实现将回调函数通过  promise.then(callback)的形式来写。但是我们的目标是配合generator,真正实现如丝般顺滑的同步化写法,如何配合呢,看这段代码:

var fs = require('fs');  var readFile = function(fileName) {   return new Promise(function(resolve, reject) {     fs.readFile(fileName, function(err, data) {       if (err) {         reject(err);       } else {         resolve(data);       }     })   }) }  //将读文件的过程放在generator中 var gen = function*() {   var data = yield readFile('./file1');   console.log(data.toString());   data = yield readFile('./file2');   console.log(data.toString()); }  //手动执行generator var g = gen(); var another = g.next(); //another.value就是返回的promise对象 another.value.then(function(data) {   //再次调用g.next从断点处执行generator,并将data作为参数传回   var another2 = g.next(data);   another2.value.then(function(data) {     g.next(data);   }) })

上述代码中,我们在generator中yield了readFile,回调语句代码写在yield之后的代码中,完全是同步的写法,实现了文章一开头的设想。

而yield之后,我们得到的是一个another.value是一个promise对象,我们可以使用then语句定义回调函数,函数的内容呢,则是将读取到的data返回给generator并继续让generator从断点处执行。

基本上这就是异步回调同步化最核心的原理,事实上如果大家熟悉python,会知道python中有"协程"的概念,基本上也是使用generator来实现的(我想当怀疑es6的generator就是借鉴了python~)

不过呢,上述代码我们依然是手动执行的。那么同上一篇一样,我们还需要实现一个run函数,用于管理generator的流程,让它能够自动跑起来!

3. 让同步化回调函数自动跑起来:一个run函数的编写

仔细观察上一段代码中手动执行generator的部分,也能发现一个规律,这个规律让我们可以直接写一个递归的函数来代替:

var run=function(gen){   var g;   if(typeof gen.next==='function'){     g=gen;   }else{     g=gen();   }    function next(data){     var tmp=g.next(data);     if(tmp.done){       return ;     }else{       tmp.value.then(next);     }   }    next(); }

函数接收一个generator,并让其中的异步能够自动执行。使用这个run函数,我们来让上一个异步代码自动执行:

var fs = require('fs');  var run = function(gen) {   var g;   if (typeof gen.next === 'function') {     g = gen;   } else {     g = gen();   }    function next(data) {     var tmp = g.next(data);     if (tmp.done) {       return;     } else {       tmp.value.then(next);     }   }    next(); }  var readFile = function(fileName) {   return new Promise(function(resolve, reject) {     fs.readFile(fileName, function(err, data) {       if (err) {         reject(err);       } else {         resolve(data);       }     })   }) }  //将读文件的过程放在generator中 var gen = function*() {   var data = yield readFile('./file1');   console.log(data.toString());   data = yield readFile('./file2');   console.log(data.toString()); } //下面只需要将gen放入run当中即可自动执行 run(gen);

执行上述代码,即可看到终端依次打印出了file1和file2的内容。

需要指出的是,这里的run函数为了简单起见只支持promise,而实际的co函数还支持thunk等。

这样一来,co函数的两大功能基本就完整介绍了,一个是洋葱模型的流程控制,另一个是异步同步化代码的自动执行。

以上就是如何深入探析koa中的异步回调处理,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何深入探析koa中的异步回调处理

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

深入浅析NodeJs并发异步的回调处理

这里说并发异步,并不准确,应该说连续异步。NodeJs单线程异步的特性,直接导致多个异步同时进行时,无法确定最后的执行结果来回调。举个简单的例子:for(var i = 0; i < 5; i++) {fs.readFile('file',
2022-06-04

深入浅析Servlet 3.0/3.1 中的异步处理

深入浅析Servlet 3.0/3.1 中的异步处理?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。在Servlet 3.0之前,Servlet采用Thread-Per-Requ
2023-05-31

深入解析PHP异常处理机制:如何确保程序的稳健性与安全性

PHP异常处理机制怎样保证安全性在PHP开发中,异常处理是至关重要的。它不仅帮助我们处理程序运行中出现的错误,而且还能提高代码的健壮性和可维护性。然而,如果不正确使用异常处理机制,可能会引入安全风险。本文将探讨PHP异常处理机制如何确保程序的安全性。一、理
深入解析PHP异常处理机制:如何确保程序的稳健性与安全性
PHP2024-12-21

深入解析PHP并发处理中的超时问题:如何优化和避免

在PHP中,处理并发请求时可能会遇到超时问题。超时是当一个请求在给定的时间内没有得到响应时,该请求将被丢弃。这可能会导致用户体验不佳,甚至可能导致服务器崩溃。因此,了解如何处理超时是非常重要的。首先,我们需要了解什么是超时。超时是指一个请求在给定的时间内没有得到响应时,该请求将
深入解析PHP并发处理中的超时问题:如何优化和避免
PHP2024-12-19

编程热搜

目录