当前位置: 首页 > news >正文

需要网站建设的人多吗互联网行业是什么

需要网站建设的人多吗,互联网行业是什么,做网站好还是网页好,html简单网站成品免费前言用了那么多年的express.js#xff0c;终于有时间来深入学习express#xff0c;然后顺便再和koa2的实现方式对比一下。老实说#xff0c;还没看express.js源码之前#xff0c;一直觉得express.js还是很不错的#xff0c;无论从api设计#xff0c;还是使用上都是可以的…前言用了那么多年的express.js终于有时间来深入学习express然后顺便再和koa2的实现方式对比一下。老实说还没看express.js源码之前一直觉得express.js还是很不错的无论从api设计还是使用上都是可以的。但是这次阅读完express代码之后我可能改变想法了。虽然express.js有着精妙的中间件设计但是以当前js标准来说这种精妙的设计在现在可以说是太复杂。里面的层层回调和递归不花一定的时间还真的很难读懂。而koa2的代码呢简直可以用四个字评论精简彪悍仅仅几个文件用上最新的js标准就很好实现了中间件代码读起来一目了然。老规矩读懂这篇文章我们依然有一个简单的demo来演示 express-vs-koa1、express用法和koa用法简单展示如果你使用express.js启动一个简单的服务器那么基本写法应该是这样const express require(express)const app express() const router express.Router()app.use(async (req, res, next) {console.log(I am the first middleware)next()console.log(first middleware end calling) }) app.use((req, res, next) {console.log(I am the second middleware)next()console.log(second middleware end calling) })router.get(/api/test1, async(req, res, next) {console.log(I am the router middleware /api/test1)res.status(200).send(hello) })router.get(/api/testerror, (req, res, next) {console.log(I am the router middleware /api/testerror)throw new Error(I am error.) })app.use(/, router)app.use(async(err, req, res, next) {if (err) {console.log(last middleware catch error, err)res.status(500).send(server Error)return}console.log(I am the last middleware)next()console.log(last middleware end calling) })app.listen(3000) console.log(server listening at port 3000) 换算成等价的koa2那么用法是这样的const koa require(koa) const Router require(koa-router)const app new koa() const router Router()app.use(async(ctx, next) {console.log(I am the first middleware)await next()console.log(first middleware end calling) })app.use(async (ctx, next) {console.log(I am the second middleware)await next()console.log(second middleware end calling) })router.get(/api/test1, async(ctx, next) {console.log(I am the router middleware /api/test1)ctx.body hello })router.get(/api/testerror, async(ctx, next) {throw new Error(I am error.) })app.use(router.routes())app.listen(3000) console.log(server listening at port 3000) 如果你还感兴趣原生nodejs启动服务器是怎么使用的可以参考demo中的这个文件node.js于是二者的使用区别通过表格展示如下(知乎不支持markdown也是醉了~表格只能截图了~)上表展示了二者的使用区别从初始化就看出koa语法都是用的新标准。在挂载路由中间件上也有一定的差异性这是因为二者内部实现机制的不同。其他都是大同小异的了。那么接下去我们的重点便是放在二者的中间件的实现上。2、express.js中间件实现原理我们先来看一个demo展示了express.js的中间件在处理某些问题上的弱势。demo代码如下const express require(express)const app express()const sleep (mseconds) new Promise((resolve) setTimeout(() {console.log(sleep timeout...)resolve() }, mseconds))app.use(async (req, res, next) {console.log(I am the first middleware)const startTime Date.now()console.log( start ${req.method} ${req.url}, { query: req.query, body: req.body });next()const cost Date.now() - startTimeconsole.log( end ${req.method} ${req.url} ${res.statusCode} - ${cost} ms) }) app.use((req, res, next) {console.log(I am the second middleware)next()console.log(second middleware end calling) })app.get(/api/test1, async(req, res, next) {console.log(I am the router middleware /api/test1)await sleep(2000)res.status(200).send(hello) })app.use(async(err, req, res, next) {if (err) {console.log(last middleware catch error, err)res.status(500).send(server Error)return}console.log(I am the last middleware)await sleep(2000)next()console.log(last middleware end calling) })app.listen(3000) console.log(server listening at port 3000) 该demo中当请求/api/test1的时候打印结果是什么呢I am the first middlewarestart GET /api/test1 I am the second middleware I am the router middleware /api/test1 second middleware end callingend GET /api/test1 200 - 3 ms sleep timeout...如果你清楚这个打印结果的原因想必对express.js的中间件实现有一定的了解。我们先看看第一节demo的打印结果是I am the first middleware I am the second middleware I am the router middleware /api/test1 second middleware end calling first middleware end calling这个打印符合大家的期望但是为什么刚才的demo打印的结果就不符合期望了呢二者唯一的区别就是第二个demo加了异步处理。有了异步处理整个过程就乱掉了。因为我们期望的执行流程是这样的I am the first middlewarestart GET /api/test1 I am the second middleware I am the router middleware /api/test1 sleep timeout... second middleware end callingend GET /api/test1 200 - 3 ms那么是什么导致这样的结果呢我们在接下去的分析中可以得到答案。2.1、express挂载中间件的方式要理解其实现我们得先知道express.js到底有多少种方式可以挂载中间件进去熟悉express.js的童鞋知道吗知道的童鞋可以心里默默列举一下。目前可以挂载中间件进去的有(HTTP Method指代那些http请求方法诸如Get/Post/Put等等)app.useapp.[HTTP Method]app.allapp.paramrouter.allrouter.userouter.paramrouter.[HTTP Method]2.2、express中间件初始化express代码中依赖于几个变量(实例)app、router、layer、route这几个实例之间的关系决定了中间件初始化后形成一个数据模型画了下面一张图片来展示图中存在两块Layer实例挂载的地方也不一样以express.js为例子我们通过调试找到更加形象的例子结合二者我们来聊聊express中间件初始化。为了方便我们把上图1叫做初始化模型图上图2叫做初始化实例图看上面两张图我们抛出下面几个问题搞懂问题便是搞懂了初始化。初始化模型图Layer实例为什么分两种初始化模型图Layer实例中route字段什么时候会存在初始化实例图中挂载的中间件为什么有7个初始化实例图中圈2和圈3的route字段不一样而且name也不一样为什么初始化实例图中的圈4里也有Layer实例这个时候的Layer实例和上面的Layer实例不一样吗首先我们先输出这样的一个概念Layer实例是path和handle互相映射的实体每一个Layer便是一个中间件。这样的话我们的中间件中就有可能嵌套中间件那么对待这种情形express就在Layer中做手脚。我们分两种情况挂载中间件使用app.use、router.use来挂载的app.use经过一系列处理之后最终也是调用router.use的使用app.all、app.[Http Method]、app.route、router.all、router.[Http Method]、router.route来挂载的app.all、app.[Http Method]、app.route、router.all、router.[Http Method]经过一系列处理之后最终也是调用router.route的因此我们把焦点聚焦在router.use和router.route这两个方法。2.2.1、router.use该方法的最核心一段代码是for (var i 0; i callbacks.length; i) {var fn callbacks[i];if (typeof fn ! function) {throw new TypeError(Router.use() requires a middleware function but got a gettype(fn))}// add the middlewaredebug(use %o %s, path, fn.name || anonymous)var layer new Layer(path, {sensitive: this.caseSensitive,strict: false,end: false}, fn);// 注意这个route字段设置为undefinedlayer.route undefined;this.stack.push(layer); } 此时生成的Layer实例对应的便是初始化模型图1指示的多个Layer实例此时以express.js为例子我们看初始化实例图圈1的所有Layer实例会发现除了我们自定义的中间件(共5个)还有两个系统自带的看初始化实例图的Layer的名字分别是query和expressInit。二者的初始化是在[application.js]中的lazyrouter方法app.lazyrouter function lazyrouter() {if (!this._router) {this._router new Router({caseSensitive: this.enabled(case sensitive routing),strict: this.enabled(strict routing)});this._router.use(query(this.get(query parser fn))); // 最终调用的就是router.use方法this._router.use(middleware.init(this)); // 最终调用的就是router.use方法} }; 于是回答了我们刚才的第三个问题。7个中间件2个系统自带、3个APP级别的中间、2个路由级别的中间件2.2.2、router.route我们说过app.all、app.[Http Method]、app.route、router.all、router.[Http Method]经过一系列处理之后最终也是调用router.route的所以我们在demo中的express.js使用了两次app.get其最后调用了router.route我们看该方法核心实现proto.route function route(path) {var route new Route(path);var layer new Layer(path, {sensitive: this.caseSensitive,strict: this.strict,end: true}, route.dispatch.bind(route));layer.route route;this.stack.push(layer);return route; }; 这么简单的实现与上一个方法的实现唯一的区别就是多了new Route这个。通过二者对比我们可以回答上面的好几个问题初始化模型图Layer实例为什么分两种? 因为调用方式的不同决定了Layer实例的不同第二种Layer实例是挂载在route实例之下的。初始化模型图Layer实例中route字段什么时候会存在使用router.route的时候就会存在初始化实例图中圈2和圈3的route字段不一样而且name也不一样为什么圈2的Layer因为我们使用箭头函数不存在函数名所以name是anonymous但是圈3因为使用的router.route所以其统一的回调函数都是route.dispath因此其函数名字都统一是bound dispatch同时二者的route字段是否赋值也一目了然最后一个问题既然实例化route之后route有了自己的Layer那么它的初始化又是在哪里的初始化核心代码// router/route.js/Route.prototype[method] for (var i 0; i handles.length; i) {var handle handles[i];if (typeof handle ! function) {var type toString.call(handle);var msg Route. method () requires a callback function but got a typethrow new Error(msg);}debug(%s %o, method, this.path)var layer Layer(/, {}, handle);layer.method method;this.methods[method] true;this.stack.push(layer);} 可以看到新建的route实例维护的是一个path对应多个method的handle的映射。每一个method对应的handle都是一个layerpath统一为/。这样就轻松回答了最后一个问题了。至此再回去看初始化模型图相信大家可以有所明白了吧~2.3、express中间件的执行逻辑整个中间件的执行逻辑无论是外层Layer还是route实例的Layer都是采用递归调用形式一个非常重要的函数next()实现了这一切这里做了一张流程图希望对你理解这个有点用处我们再把express.js的代码使用另外一种形式实现这样你就可以完全搞懂整个流程了。为了简化我们把系统挂载的两个默认中间件去掉把路由中间件去掉一个最终的效果是((req, res) {console.log(I am the first middleware);((req, res) {console.log(I am the second middleware);(async(req, res) {console.log(I am the router middleware /api/test1);await sleep(2000)res.status(200).send(hello)})(req, res)console.log(second middleware end calling);})(req, res)console.log(first middleware end calling) })(req, res) 因为没有对await或者promise的任何处理所以当中间件存在异步函数的时候因为整个next的设计原因并不会等待这个异步函数resolve,于是我们就看到了sleep函数的打印被放在了最后面并且第一个中间件想要记录的请求时间也变得不再准确了~但是有一点需要申明的是虽然打印变得奇怪但是绝对不会影响整个请求因为response是在我们await之后所以请求是否结束还是取决于我们是否调用了res.send这类函数至此希望整个express中间件的执行流程你可以熟悉一二更多细节建议看看源码这种精妙的设计确实不是这篇文章能够说清楚的。本文只是想你在面试的过程中可以做到有话要说~接下去我们分析牛逼的Koa2这个就不需要费那么大篇幅去讲因为实在是太太容易理解了。3、koa2中间件koa2中间件的主处理逻辑放在了koa-compose也就是仅仅一个函数的事情function compose (middleware) {if (!Array.isArray(middleware)) throw new TypeError(Middleware stack must be an array!)for (const fn of middleware) {if (typeof fn ! function) throw new TypeError(Middleware must be composed of functions!)}/*** param {Object} context* return {Promise}* api public*/return function (context, next) {// last called middleware #let index -1return dispatch(0)function dispatch (i) {if (i index) return Promise.reject(new Error(next() called multiple times))index ilet fn middleware[i]if (i middleware.length) fn nextif (!fn) return Promise.resolve()try {return Promise.resolve(fn(context, dispatch.bind(null, i 1)));} catch (err) {return Promise.reject(err)}}} } 每个中间件调用的next()其实就是这个dispatch.bind(null, i 1)还是利用闭包和递归的性质一个个执行并且每次执行都是返回promise所以最后得到的打印结果也是如我们所愿。那么路由的中间件是否调用就不是koa2管的这个工作就交给了koa-router这样koa2才可以保持精简彪悍的风格。再贴出koa中间件的执行流程吧最后有了这篇文章相信你再也不怕面试官问你express和koa的区别了~参考koaexpresshttp
http://www.zqtcl.cn/news/194728/

相关文章:

  • 农业网站素材wordpress all in one
  • 学习网站建设有前景没wordpress 和dokuwiki
  • 服装网站开发方案网站设计美工排版编辑
  • 旅游网站首页模板下载广州市建设工程检测中心网站
  • 餐饮加盟网站建设wordpress 首行缩进
  • kkday是哪里做的网站橙云 php网站建设
  • 站长之家0网站规划作品
  • 物流公司网站建设系统规划广告设计怎么学
  • 异地备案 网站中信建设有限责任公司经济性质
  • 网站没有备案怎么申请广告宿迁莱布拉网站建设
  • 太原适合网站设计地址网站建设 教学视频教程
  • 建商城网站需要多少钱网站开发维护报价单
  • 唐山网站建设冀icp备婚纱网站页面设计
  • 做购物网站支付需要怎么做手机网站建设教程
  • 国外网站空间租用哪个好建站快车打电话
  • 自媒体网站 程序做药公司的网站前置审批
  • 简洁网站模板素材廊坊建设企业网站
  • 长沙建站找有为太极就治就网站内容如何自动关联新浪微博
  • 手机企业网站设计理念企业建设网站的步骤是什么?
  • 网站建设与管理视频网站推广的方法枫子
  • 苏州市住房和城乡建设局官方网站宠物之家网站开发
  • 建个人网站活字格能开发企业网站吗
  • php网站后台密码忘记做电子商务网站 语言
  • 网站建设策划师怎样进入国外网站
  • 建设银行商城网站浙江建站管理系统价格
  • 我想做个网站怎么做的常用的网络营销方法及效果
  • 南通专业做网站南宁网站建设mxfsem
  • 阿里巴巴电子商务网站建设目的网站专题素材
  • 浙江虎霸建设机械有限公司网站哪个网站做简历好
  • 网站做电商资质吗网站开发作品