位置: 编程技术 - 正文

Node.js中看JavaScript的引用(node.js java 性能)

编辑:rootadmin

推荐整理分享Node.js中看JavaScript的引用(node.js java 性能),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:node.js java 性能,nodejs调用java方法,node.js jwt,node.js java,nodejs jvm,node.js javascript,node.js java,node.js java,内容如对您有帮助,希望把文章链接给更多的朋友!

早期学习 Node.js 的时候 (-),有挺多是从 PHP 转过来的,当时有部分人对于 Node.js 编辑完代码需要重启一下表示麻烦(PHP不需要这个过程),于是社区里的朋友就开始提倡使用 node-supervisor 这个模块来启动项目,可以编辑完代码之后自动重启。不过相对于 PHP 而言依旧不够方便,因为 Node.js 在重启以后,之前的上下文都丢失了。

虽然可以通过将 session 数据保存在数据库或者缓存中来减少重启过程中的数据丢失,不过如果是在生产的情况下,更新代码的重启间隙是没法处理请求的(PHP可以,另外那个时候 Node.js 还没有 cluster)。由于这方面的问题,加上本人是从 PHP 转到 Node.js 的,于是从那时开始思考,有没有办法可以在不重启的情况下热更新 Node.js 的代码。

最开始把目光瞄向了 require 这个模块。想法很简单,因为 Node.js 中引入一个模块都是通过 require 这个方法加载的。于是就开始思考 require 能不能在更新代码之后再次 require 一下。尝试如下:

a.js

b.js

两个 JS 文件写好之后,从 a.js 启动,刷新页面会输出 b.js 中的 ,然后修改 b.js 文件中导出的值,例如修改为 。再次刷新页面依旧是原本的 。

再次执行一次 require 并没有刷新代码。require 在执行的过程中加载完代码之后会把模块导出的数据放在 require.cache 中。require.cache 是一个 { } 对象,以模块的绝对路径为 key,该模块的详细数据为 value。于是便开始做如下尝试:

a.js

再次 require 之前,将 require 之上关于该模块的 cache 清理掉后,用之前的方法再次测试。结果发现,可以成功的刷新 b.js 的代码,输出新修改的值。

了解到这个点后,就想通过该原理实现一个无重启热更新版本的 node-supervisor。在封装模块的过程中,出于情怀的原因,考虑提供一个类似 PHP 中 include 的函数来代替 require 去引入一个模块。实际内部依旧是使用 require 去加载。以b.js为例,原本的写法改为 var b = include(‘./b'),在文件 b.js 更新之后 include 内部可以自动刷新,让外面拿到最新的代码。

但是实际的开发过程中,这样很快就碰到了问题。我们希望的代码可能是这样:

web.js

但按照这个目标封装include的时候,我们发现了问题。无论我们在include.js内部中如何实现,都不能像开始那样拿到新的 b.num。

对比开始的代码,我们发现问题出在少了 b = xx。也就是说这样写才可以:

web.js

修改成这样,就可以保证每次能可以正确的刷新到最新的代码,并且不用重启实例了。读者有兴趣的可以研究这个include是怎么实现的,本文就不深入讨论了,因为这个技巧使用度不高,写起起来不是很优雅[1],反而这其中有一个更重要的问题——JavaScript的引用。

JavaScript 的引用与传统引用的区别

要讨论这个问题,我们首先要了解 JavaScript 的引用于其他语言中的一个区别,在 C++ 中引用可以直接修改外部的值:

而在 JavaScript 中:

我们发现与 C++ 不同,根据上面代码 ① 可知 JavaScript 中并没有传递一个引用,而是拷贝了一个新的变量,即值传递。根据 ② 可知拷贝的这个变量是一个可以访问到对象属性的“引用”(与传统的 C++ 的引用不同,下文中提到的 JavaScript 的引用都是这种特别的引用)。这里需要总结一个绕口的结论:Javascript 中均是值传递,对象在传递的过程中是拷贝了一份新的引用。

为了理解这个比较拗口的结论,让我们来看一段代码:

通过这个例子我们可以看到,data 虽然像一个引用一样指向了 obj.data,并且通过 data 可以访问到 obj.data 上的属性。但是由于 JavaScript 值传递的特性直接修改 data = xxx 并不会使得 obj.data = xxx。

打个比方最初设置 var data = obj.data 的时候,内存中的情况大概是:

| Addr | 内容 | |----------|-------- | obj.data | 内存1 || data | 内存1 |

所以通过 data.xx 可以修改 obj.data 的内存1。

然后设置 data = xxx,由于 data 是拷贝的一个新的值,只是这个值是一个引用(指向内存1)罢了。让它等于另外一个对象就好比:

Node.js中看JavaScript的引用(node.js java 性能)

| Addr | 内容 | |----------|-------- | obj.data | 内存1 || data | 内存2 |

让 data 指向了新的一块内存2。

如果是传统的引用(如上文中提到的 C++ 的引用),那么 obj.data 本身会变成新的内存2,但 JavaScript 中均是值传递,对象在传递的过程中拷贝了一份新的引用。所以这个新拷贝的变量被改变并不影响原本的对象。

Node.js 中的 module.exports 与 exports

上述例子中的 obj.data 与 data 的关系,就是 Node.js 中的 module.exports 与 exports 之间的关系。让我们来看看 Node.js 中 require 一个文件时的实际结构:

所以很自然的:

Node.js 中的 exports 就是拷贝的一份 module.exports 的引用。通过 exports 可以修改Node.js 当前文件导出的属性,但是不能修改当前模块本身。通过 module.exports 才可以修改到其本身。表现上来说:

这是二者表现上的区别,其他方面用起来都没有差别。所以你现在应该知道写module.exports.xx = xxx; 的人其实是多写了一个module.。

更复杂的例子

为了再练习一下,我们在来看一个比较复杂的例子:

按照开始的结论我们可以一步步的来看这个问题:

内部结构:

| Addr | 内容 | |---------|-------------|| a | 内存1 {n:1} | | b | 内存1 |

继续往下看:

a 虽然是引用,但是 JavaScript 是值传的这个引用,所以被修改不影响原本的地方。

| Addr | 内容 | |-----------|-----------------------|| 1) a | 内存2({n:2}) | | 2) 内存1.x | 内存2({n:2}) || 3) b | 内存1({n:1, x:内存2}) |

所以最后的结果

a.x 即(内存2).x ==> {n: 2}.x ==> undefinedb.x 即(内存1).x ==> 内存2 ==> {n: 2}

总结

JavaScrip t中没有引用传递,只有值传递。对象(引用类型)的传递只是拷贝一个新的引用,这个新的引用可以访问原本对象上的属性,但是这个新的引用本身是放在另外一个格子上的值,直接往这个格子赋新的值,并不会影响原本的对象。本文开头所讨论的 Node.js 热更新时碰到的也是这个问题,区别是对象本身改变了,而原本拷贝出来的引用还指向旧的内存,所以通过旧的引用调用不到新的方法。

Node.js 并没有对 JavaScript 施加黑魔法,其中的引用问题依旧是 JavaScript 的内容。如 module.exports 与 exports 这样隐藏了一些细节容易使人误会,本质还是 JavaScript 的问题。

注[1]:

老实说,模块在函数内声明有点谭浩强的感觉。

把 b = include(xxx) 写在调用内部,还可以通过设置成中间件绑定在公共地方来写。

除了写在调用内部,也可以导出一个工厂函数,每次使用时 b().num 一下调用也可以。

还可以通过中间件的形式绑定在框架的公用对象上(如:ctx.b = include(xxx))。

要实现这样的热更新必须在架构上就要严格避免旧代码被引用的可能性,否则很容易写出内存泄漏的代码。

以上所述是小编给大家介绍的Node.js中看JavaScript的引用,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对积木网网站的支持!

nodejs 终端打印进度条实例代码 1.场景导入当我们对大量文件进行批量处理的时候(例如:上传/下载、保存、编译等),常常希望知道当前进展如何,或者失败(成功)的任务有多少;当我

Node.js中的require.resolve方法使用简介 前言网上关于NodeJs的论述很多,此处不多说。个人认为,NodeJs的编程思想和客户端Javascript保持了一种理念,没有什么变化,只是增加了require()函数,因

Node+Express+MongoDB实现登录注册功能实例 注入MongoDB依赖varmongoose=require("mongoose");由于需要进行表单处理,需要用到bodyParser中间件bodyParser模块来做文件解析,将表单里的数据进行格式化varbodyParse

标签: node.js java 性能

本文链接地址:https://www.jiuchutong.com/biancheng/379418.html 转载请保留说明!

上一篇:在node中如何使用 ES6(node的使用)

下一篇:nodejs 终端打印进度条实例代码(nodejs调用打印机驱动)

  • 个体户超过了核定征收额怎么交税
  • 增值税需要年度报税吗
  • 税务师考试咨询电话
  • 如何理解中医的补
  • 农副产品商贸公司标语
  • 增值税未缴款能清卡吗
  • 现流表怎么编
  • 没有报关单可以结汇吗
  • 农产品普通发票抵扣政策
  • 销项发票导出格式不对怎么办
  • 预提费用所得税前扣除
  • 企业想成为退税商店需具备哪些条件
  • 住房公积金比例一般是多少
  • 土地出让要不要交印花税吗
  • 税收滞纳金可以免除吗
  • 应计利息会计分录处理
  • 个税父母赡养抵扣3000
  • 劳务派遣个人所得税
  • 培训学校预收学费要交税吗
  • 银行收到理财资金怎么做账
  • 实收资本属于会计科目吗
  • 集体土地上的不动产能符合异议28条规定吗
  • 固定资产评估增值递延所得税
  • 30万的装修工程利润一般是多少
  • 房地产开发公司取名
  • 汽车维修单位提成比例
  • 债务重组会计处理中,债务人确认的债务重组利得
  • 金税盘抄税报税清卡流程图
  • 增值税一般纳税人是什么意思
  • 通过拍卖取得的车牌号,过期了怎么办
  • 企业技术开发的原则
  • 双cpu只有一个运行
  • 企业纳税申报的流程
  • 暂估成本后发票怎么入账
  • 仓储费用结算方式有哪些
  • 酒店损益类科目包括哪些
  • vue实现导出
  • 工业企业在进行材料采购
  • 增值税专用发票丢了怎么补救
  • php文件修改后,打开还是显示以前的页面
  • 暂估和开票的差别是什么
  • vue图片放在哪里
  • Vue3通透教程【十二】TS类型声明优势
  • mac apache php
  • 如何在最新版本钉钉上使用支付审申请
  • 采购的技术服务费需入库吗
  • 工会经费的会计分录2022
  • 出售持有股票会计处理
  • 国家税务总局关于营改增后土地增值税
  • 织梦怎么添加相关
  • sql server概述
  • 实收资本报表怎么填
  • 息税前利润变动率怎么算
  • 背书转让的操作
  • 记账凭证摘要的填制要求
  • 坏账准备的帐务处理
  • 接受捐赠做账
  • 资产负债表怎么看财务状况
  • 启动sqlserver服务的命令
  • mysql 5.6 5.7 性能
  • 最基本的长度单位是什么
  • sql server real
  • navicate创建存储过程
  • centos 7.5 7.6
  • solaris安装软件包
  • sysscjh.exe是什么文件
  • linux的发展
  • linux 文件数量 命令
  • opengl csdn
  • javascript事件委托的用法及其好处简析
  • 自制u盘杀手
  • 浅析学校德育的个体智能发展功能
  • nodejs搭建本地资源服务器
  • 关于jquery的事件冒泡,以下描述正确的是
  • 基于JAVASCRIPT实现的可视化工具是
  • python生成pyc
  • 消防咨询电话24小时
  • 广东电子税务局财务报表在哪里查询
  • 合并方为进行企业合并发生的佣金和手续费怎么处理?
  • 从日本带化妆品回国会被扣吗
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设