Nodejs -- 流程控制库

流程控制库

尾触发和next

尾触发最多的应用是在Connect的中间件

var app = connect()
app.use(connect.staticCache())
app.use(connect.static(__dirname + '/public'))
app.use(conect.cokkieParser())
app.use(connect.session())
app.use(connect.query())
app.use(connect.bodyParser())
app.use(connect.csrf())
app.listen(3001)

通过use方法注册一系列的中间件,监听端口上的请求,中间件利用了尾触发的机制。

function (req, res, next) {
// 中间件
}

每个中间件传递请求对象,响应对象和尾触发的函数,通过队列形成一个处理流
在这里插入图片描述

中间件机制使得在处理网络请求的时候,可以向切面编程一样过滤,验证,日志等共嗯那个。不会与具体业务产生关联
Connect的核心代码

// 创建了http服务器的request事件处理函数
function createServer() {
    function app(req, res) {
        app.handle(req, res)
    }
    utils.merge(app, proto)
    utils.merge(app, EventEmitter.prototype)
    app.route = '/'
    app.stack = []
    for (var i = 0; i < arguments.length; i++) {
        app.use(arguments[i])
    }
    return app
}

function app(req, res) {app.handle(req, res)} 通过这个代码创建了http服务器的request事件处理函数。真正核心的代码是app.stack=[] stack属性是服务器内部维护的中间件队列,通过调用use方法可以将中间件放到队列中。

app.use = function(route,fn) {
    this.stack.push({route: route, handle fn})
    return this
}

此时就建立好了模型,通过整合原生的http模块就可以实现监听。监听函数的实现

app.listen = function() {
    var serve = http.createServer(this)
    return server.listen.apply(serve, arguments)
}
app.handle = function(req, res, out) {
    next()
}

原始的next()方法较为复杂,简化后: 取出队列中的中间件并执行,同时传入当前方法实现链式调用。达到持续触发的目的

function next(node) {
    layer = stack[index++]
    layer.handle(req, res, next)
}

可以参考connect的流式处理模式。尽管中间件这种尾触发的模式不要求每个中间方法都是异步的,但是如果每个步骤都可以采用异步来完成,实际上只是串行化的处理,没有办法通过并行的异步调用来提升业务的处理效率,流式处理只是可以将一些串行的逻辑扁平化,但是并行逻辑处理还是需要搭配事件或者promise完成。
在connect中,尾触发适合处理网络请求的场景。将复杂的处理逻辑拆解为简介,单一的处理单元,逐层次的处理请求对象和响应对象。

async

async是流程控制模块,流程控制是开发过程中的基本需求,async提供了20多种的方法用于处理异步的各种写作模块
async提供了series()方法来实现一组任务的串行执行。

async.series([
    function(callback) {
        fs.readFile('file1.txt', 'utf-8', callback)
    }
    function(callback) {
        fs.readFile('file2.txt', 'utf-8', callback)
    }
], function(err, result) {
    // results => [file1.txt, file2.txt]
})

等价于

fs.readFile('file1.txt','utf-8', function(err, content) {
    if (err) {
        return callback(err)
    }    
    fs.readFile('file2.txt','utf-8', function(err, data) {
        if(err) {
            return callback(err)
        }
        callback(null, [content, data])
    })
}) 

series()方法中传入的函数callback()并非是由使用者指定,事实上,此处的回调函数通过async经过高阶函数的方式注入,这里隐含了特殊的逻辑,每个callback()执行的时候都会将结果保存起来,然后执行到下一个调用,直到结束所有的调用,最终的回调函数执行的时候,队列中的异步调用保存到结果通过数组的方式传入。

异步的并行执行

当需要通过并行来提升性能的时候,async提供了parallel方法,通过并行执行一些异步操作

async.parallel([
    function(callback) {
        fs.readFile('file1.txt', 'utf-8', callback)
    },
    function(callback) {
        fs.readFile('file2.txt', 'utf-8', callback)
    }
],function(err, results) {
    // results => ['file1.txt', 'file2.txt']
})
// 等价于
var counter = 2
var results = []
var done = function(index, value) {
    results[index] = value
    counter--
    if(counter == 0) {
        callback(null, results)
    }
}
var hasErr = false 
var fail = function(err) {
    if(!hasErr) {
        hasErr = true
        callback(err)
    }
}
fs.readFile('file.txt', 'utf-8', function(err, content) {
    if (err) {
        return fail(err)
    }
    done(0, data)
}) 
fs.readFile('file2.txt','utf-8', function(err, data) {
    if (err) {
        return fail(err)
    }
    done(1, data)
})

同样,通过async编写的代码既没有深度的嵌套,也灭有复杂的状态判断,parallel()方法对于异常的判断是一旦某个异步调用产生了异常,就会将异常作为第一个参数传入给最终的回调函数,只有所有的异步调用都正常完成的时候,才会将结果以数组的形式传入。
EventProxy[前几篇中有] 是基于事件发布/订阅模式设计的,也用到了async相同的原理,通过特殊的回调函数来返回隐含返回值的处理,不同的是在async这个架构中,这个回调函数是通过async封装后传递出来的,但是EventProxy是通过done和fail方法来产生新的回调函数,这两种方法都是高阶函数的应用

异步调用的依赖处理

series()适合无依赖的异步串行。当前一个是后一个调用的输入,series()无法满足需求。async提供了waterfall()方法。

async.waterfall([
    function(callback) {
        fs.readFile('file1.txt', 'utf-8', function(err,data) {
            callback(err, content)
        })
    },
    function (arg1, callback) {
        fs.readFile(arg1, 'utf-8', function(err, content) {
            callback(err, content)
        })
    }
], function (err, result) {
    // result => file4.txt
})

等价于

fs.readFile('file1.txt', 'utf-8', function(err, data) {
    if (err) {
        return callback(err)
    }
    fs.readFile(data1, 'utf-8', function (err, data2) {
    if (err) {
        return callback(err)
    }
    fs.readFile(data2, 'utf-8', function (err, data3) {    
    if (err) {
    return callback(err);
    }
    callback(null, data3)
    })
    })
})    

自动依赖处理

业务如下

1. 从磁盘读取配置文件
2. 链接mongodb
3. 配置文件链接redis
4. 编译静态文件
5. 上传cdn
6. 启动服务器

伪代码

readConfig: function() {}
connectMongoDB: function() {}
connectRedis: function() {}
complieAsserts: function() {}
uploadAsserts: function() {}
startup: function() {}

代码实现

var deps = {
  readConfig: function (callback) {
    // read config file
    callback();
  },
  connectMongoDB: [
    "readConfig",
    function (callback) {
      // connect to mongodb
      callback();
    },
  ],
  connectRedis: [
    "readconfig",
    function (callback) {
      // connect to redis
    },
  ],
  complieAsserts: function (callback) {
    // complie asserts
    callback();
  },
  uploadAsserts: [
    "complieAsserts",
    function (callback) {
      // upload to assert
      callback();
    },
  ],
  startup: [
    "connectMongoDB",
    "connectRedis",
    "uploadAsserts",
    function (callback) {
      // startup
    },
  ],
};

auto()方法可以根据依赖关系自动分析,以最佳的顺序执行上面的业务async.auto(deps)

proxy.assp('readtheconfig', function () {
    // read config file
    proxy.emit('readConfig');
}).on('readConfig', function () {
    // connect to mongodb
    proxy.emit('connectMongoDB');
}).on('readConfig', function () {
    // connect to redis
    proxy.emit('connectRedis');
}).assp('complietheasserts', function () {
    // complie asserts
    proxy.emit('complieAsserts');
}).on('complieAsserts', function () {
    // upload to assert
    proxy.emit('uploadAsserts');
}).all('connectMongoDB', 'connectRedis', 'uploadAsserts', function () {
    // Startup
});

step

Step(
function readFile1() {
    fs.readFile('file1.txt', 'utf-8',this)
},
function readFile2(err,content) {
    fs.readFile('file2.txt', 'utf-8',this)
},
function done(err,content) {
    console.log(content)
}
)

step 用到了this,是step内部的一个next()方法,将异步调用的结果传递给下一个任务作为参数。

并行任务执行

this具有一个parallel()方法,告诉step,需要等待所有的任务完成才能执行下一个任务。

Step(
  function readFile1() {
    fs.readFile("file1.txt", "utf-8", this.parallel());
    fs.readFile("file2.txt", "utf-8", this.parallel());
  },
  function done(err, content1, content2) {
    // content1 => file1
    // content2 => file2
    console.log(arguments);
  }
);

wind 不加赘述

小结

  1. 事件发布/订阅模式相对算是一种较为原始的方式,Promise/Deferred模式贡献了一个非常不错的异步任务模型的抽象。promise/deferred重点在于封装异步的调用
  2. 流程控制库在于会低啊函数的注入

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/588986.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

跨平台终端软件——quardCRT

作为一个技术栈比较复杂的程序&#xff0c;工作常常会在windows/linux/macos等不同的平台切换开发&#xff0c;开发过程中最常用的就是终端工具了&#xff0c;一个趁手的终端可以成倍的提高工作效率&#xff0c;因此我一直希望能找个一个跨平台体验一致无缝切换的终端软件&…

Unity Audio Filter 入门

概述&#xff1a; 如果你在你项目中需要一些特殊的声音效果&#xff0c;那这部分声音过滤器的部分一定不要错过喔&#xff0c;让我们来学习这部分的内容吧&#xff01; 这部分理论性比较强&#xff0c;认真看我的注解哈&#xff0c;我尽量解释的易懂一点。 Audio Chorus Filter…

街道征迁项目档案管理系统

街道征迁项目档案管理系统是一个用于管理街道征迁项目档案的软件系统。该系统的主要功能包括档案录入、档案存储、档案检索、档案共享等。 系统的用户可以通过该系统录入征迁项目相关的档案信息&#xff0c;包括项目名称、征迁范围、土地面积、征迁补偿费用等。同时&#xff0c…

vue本地调试devtools

一、谷歌浏览器加载扩展程序 二、把解压的压缩包添加即可&#xff0c;重启浏览器 三、启动前端本地项目&#xff0c;即可看到Vue小图标

AD | Altium Designer(原理图设计、电路仿真、PCB绘图)汉化版

Altium Designer(原理图设计、电路仿真、PCB绘图) 通知公告 Altium Designer(AD)是一种功能强大的电子设计自动化(EDA)软件。它主要用于设计和开发电子产品,如电路板(PCB)、集成电路(IC)和嵌入式系统。AD提供了完整的设计工具套件,包括原理图设计、PCB布局、仿真、设…

ICode国际青少年编程竞赛- Python-1级训练场-识别循环规律1

ICode国际青少年编程竞赛- Python-1级训练场-识别循环规律1 1、 for i in range(4):Dev.step(6)Dev.turnLeft()2、 for i in range(3):Dev.turnLeft()Dev.step(2)Dev.turnRight()Dev.step(2)3、 for i in range(3):Spaceship.step(5)Spaceship.turnLeft()Spaceship.step(…

互联网轻量级框架整合之MyBatis底层运转逻辑

MyBatis运转过程中主要步骤有两个&#xff0c;其一读取配置文件缓存到Configuration对象&#xff0c;用于构建SqlSessionFactory&#xff1b;其二是SqlSession的执行过程&#xff0c;这其中SqlSessionFactory的构建过程相对很好理解&#xff0c;而SqlSession的执行过程就相对复…

LT6911GX HDMI2.1 至四端口 MIPI/LVDS,带音频 龙迅方案

1. 描述LT6911GX 是一款面向 VR / 显示应用的高性能 HDMI2.1 至 MIPI 或 LVDS 芯片。HDCP RX作为HDCP中继器的上游&#xff0c;可以与其他芯片的HDCP TX配合使用&#xff0c;实现中继器功能。对于 HDMI2.1 输入&#xff0c;LT6911GX 可配置为 3/4 通道。自适应均衡功能使其适合…

vue3+vite+js 实现移动端,PC端响应式布局

目前使用的是vue3vite&#xff0c;没有使用ts 纯移动端|PC端 这种适用于只适用一个端的情况 方法&#xff1a;amfe-flexible postcss-pxtorem相结合 ① 执行以下两个命令 npm i -S amfe-flexible npm install postcss-pxtorem --save-dev② main.js文件引用 import amfe-f…

FreeRTOS信号量

信号量简介 def 1&#xff1a; 信号量是一种解决问题的机制&#xff0c;可以实现共享资源的访问 信号量浅显理解例子&#xff1a; 空车位&#xff1a; 信号量资源&#xff08;计数值&#xff09; 让出占用车位&#xff1a; 释放信号量&#xff08;计数值&#xff09; 占用车…

LT6911UXB HDMI2.0 至四端口 MIPI DSI/CSI,带音频 龙迅方案

1. 描述LT6911UXB 是一款高性能 HDMI2.0 至 MIPI DSI/CSI 转换器&#xff0c;适用于 VR、智能手机和显示应用。HDMI2.0 输入支持高达 6Gbps 的数据速率&#xff0c;可为4k60Hz视频提供足够的带宽。此外&#xff0c;数据解密还支持 HDCP2.2。对于 MIPI DSI / CSI 输出&#xff0…

jvm 马士兵 01

01.JVM是什么 JVM是一个跨平台的标准 JVM只识别class文件&#xff0c;符合JVM规范的class文件都可以被识别

知乎广告开户流程,知乎广告的优势是什么?

社交媒体平台不仅是用户获取知识、分享见解的场所&#xff0c;更是品牌展示、产品推广的重要舞台。知乎作为国内知名的知识分享社区&#xff0c;以其高质量的内容生态和庞大的用户基础&#xff0c;成为了众多企业进行广告投放的优选之地。云衔科技通过其专业服务&#xff0c;助…

数字身份管理:Facebook如何利用区块链技术?

随着数字化进程的加速&#xff0c;个人身份管理已成为一个关键议题。在这方面&#xff0c;区块链技术正在逐渐展现其巨大潜力。作为全球最大的社交媒体平台&#xff0c;Facebook也在积极探索和应用区块链技术来改进其数字身份管理系统。本文将深入探讨Facebook如何利用区块链技…

<Linux> 权限

目录 权限人员相对于文件来说的分类更改权限文件的拥有者与所属组 权限 权限是操作系统用来限制对资源访问的机制&#xff0c;权限一般分为读、写、执行。系统中的每个文件都拥有特定的权限、所属用户及所属组&#xff0c;通过这样的机制来限制哪些用户、哪些组可以对特定文件…

Node私库Verdaccio使用记录,包的构建,推送和拉取

Node私库Verdaccio使用记录&#xff0c;包的构建&#xff0c;推送和拉取 Verdaccio是一个轻量级的私有npm代理注册中心&#xff0c;它可以帮助你在本地搭建一个npm仓库&#xff0c;非常适合企业内部使用。通过使用Verdaccio&#xff0c;你可以控制和缓存依赖包&#xff0c;提高…

政安晨:【Keras机器学习示例演绎】(二十七)—— 利用 NNCLR 进行自我监督对比学习

目录 简介 自我监督学习 对比学习 NNCLR 设置 超参数 加载数据集 增强 准备扩增模块 编码器结构 用于对比预训练的 NNCLR 模型 预训练 NNCLR 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望…

DRF限流组件源码分析

DRF限流组件源码分析 开发过程中&#xff0c;如果某个接口不想让用户访问过于频繁&#xff0c;可以使用限流的机制 限流&#xff0c;限制用户访问频率&#xff0c;例如&#xff1a;用户1分钟最多访问100次 或者 短信验证码一天每天可以发送50次&#xff0c; 防止盗刷。 对于…

Spring - 7 ( 13000 字 Spring 入门级教程 )

一&#xff1a;Spring Boot 日志 1.1 日志概述 日志对我们来说并不陌生&#xff0c;我们可以通过打印日志来发现和定位问题, 或者根据日志来分析程序的运行过程&#xff0c;但随着项目的复杂度提升, 我们对日志的打印也有了更高的需求, 而不仅仅是定位排查问题 比如有时需要…

【LDAP】LDAP 和 AD 介绍及使用 LDAP 操作 AD 域

LDAP 和 AD 介绍及使用 LDAP 操作 AD 域 1.LDAP入门1.1 定义1.2 目录结构1.3 命名格式 2.AD 入门2.1 AD 定义2.2 作用2.3 AD 域结构常用对象2.3.1 域&#xff08;Domain&#xff09;2.3.2 组织单位&#xff08;Organization Unit&#xff09;2.3.3 群组&#xff08;Group&#…