分享

传统后端开发者视角学习异步Nodejs的血泪笔记

 python_lover 2022-02-26

之前一直以传统后端的思维来写nodejs的代码,发现运行结果与我的同步思维方式不太一样,所以需要全面将nodejs学习一下。此学习笔记适合后端同学学习nodejs的时候观看,前端大佬可以多多指正。

环境变量

console.log(setTimeout);
console.log(setInterval);
console.log(setImmediate);
console.log(__filename); // 当前文件的全名
console.log(__dirname); //
console.log(process); // 进程信息,全局变量

process就是当前运行环境变量的集合体。例如process.argv就是获取用户输入的参数

数学库

与Java一样,叫Math

Math.random(); // 返回0~1的浮点数

模块规范之exports和module.exports的关系

需要解决的问题:

脚本变多时,需要手动管理加载顺序
不同脚本之间逻辑调用,需要通过全局变量的方式去交流,例如:JQUERY。将输出放到全局变量中,然后由其他部分进行使用
没有html怎么办?

nodejs中使用CommonJs模块规范,加载另一个js,用require函数来获取即可。

// demo.js
console.log("-----------");
let lib = require('./lib');
console.log('---------',lib);

// lib.js
console.log('==========');
exports.hello = '++++++++++';
exports.word = '///////////////';
exports.add = function () {
    console.log('1111111111111')
};

可以看见,模块中定义模块输出的方式:默认会注入一个叫export的变量,在该变量上挂参数就相当于给当前被require对象里面附一个值。还可以挂函数,对象等,理论上就是在输出对象中加对象。所以在exports中我们可以挂各种类型的结构
同时,对于exports来说,外面可以改变模块里面的内容,是同一个引用。

// demo.js
console.log("-----------");
let lib = require('./lib');
lib.addd = '*******************';
console.log('---------',lib);

// lib.js
console.log('==========');
exports.hello = '++++++++++';
exports.word = '///////////////';
exports.add = function () {
    console.log('1111111111111')
};

setTimeout(()=>{
  console.log(exports)
},2000);

运行结果如下,可以看见修改了外面被require的对象,里面的exports对象也被修改了
file

特定地,如果希望被require出来的不是一个对象,而是一个方法,或者变量啥的,可以使用module.exports,但是会覆盖掉之前怼exports变量的修改。

// demo.js
console.log("-----------");
let lib = require('./lib');
console.log('---------',lib);

// lib.js
console.log('==========');
exports.hello = '++++++++++';
exports.word = '///////////////';
exports.add = function () {
    console.log('1111111111111')
};
module.exports = function dsa() {
    return '123'
};

最终打印的结果为
file
可以看到结果中exports变量的值并没有被输出出来,得到这样的结果有两种可能性,第一是module.exports将exports对象给覆盖掉了,第二种是module.exports和exports在文件被require的时候其实是两个不同的东西,指向两个不同的内存,当模块被require的时候,如果module.exports没有被指定,那么就require出来的是exports对象,如果module.exports被指定了,那么就使用module,exports。我比较倾向于后面这种解释,下面来证实我的观点。

// demo.js
console.log("-----------");
let lib = require('./lib');
lib.addd = '*******************';
console.log('---------',lib);

// lib.js
console.log('==========');
exports.hello = '++++++++++';
exports.word = '///////////////';
exports.add = function () {
    console.log('1111111111111')
};

setTimeout(()=>{
  console.log(exports)
},2000);

module.exports = function dsa() {
    return '123'
};

setTimeout(()=>{
  console.log(module.exports)
},2000);

运行结果为:
file
可以看到,在demo.js中给引用的lib新增了addd属性,最终是作用到了module.exports上,同时,exports打印的结果与module.exports并不一样,说明,module.exports和exports不是一个对象,只是在一个模块被引用时,module.exports的优先级要高于exports。

获取控制台输入(标准输入输出)

process.stdin.on('data', (e) => {
    const x = e.toString().trim();
    console.log(x);
} );

包管理工具

每个语言都有包管理工具,不过nodejs有个坑,就是npm有时候版本和nodejs不匹配,这个时候就会抛出一些莫名其妙的错误。碰到这种情况,就只能去npm官网解决问题部分寻找结果了。

npm init

要使用npm,需要本身就是一个npm目录,所以需要使用 npm init 来声明为npm 包

package.json

dependencies:放在里面,npm install时会被自动下载,声明当前npm包所有的依赖

安装卸载
npm install xxx
npm uninstall xxx
国内镜像

npm是国外的镜像,可以使用淘宝的npm镜像,可以去NPM镜像查看相关的方法
值得注意的是,用cnpm的时候要加上--save指令,否则dependencies中不会加进去

npm search xxx

很多同学不知道自己适合用什么包,比如我想连接redis,该使用什么包呢?就可以使用 npm search redis来寻找了,相同的,docker search redis/composer search redis 等等都是这么玩的。

nodejs架构

基于V8运行环境
事件驱动:非阻塞式的IO模型

内置模块

nodejs官方网站文档页面 nodejs官方网站文档中文页面

底层能力是怎么完成的

以os为例,在源码的lib文件中:internalBinding('os') 在 src/node_os.cc中再调用v8的能力

Event模块实现观察者模式,进而使得两个对象进行传输

EventEmitter,process继承与它,所以可以往上抛事件,也就是典型的观察者模式。底层的能力封装起来放到一个模块中,外面的模块拿到这个代码,通过事件的监听器,就能比较方便的,知道子模块里面发生的变化。
观察者模式,可以用来解决两个对象的交流问题。
其实这个方法也可以实现两个函数的先后执行,从而将代码过程化,我看到这个还是比较兴奋的,这样我就可以解决本来具有先后执行顺序的代码,由于nodejs的异步特性导致无法实现的,可以利用这个模式实现

const  EventEmitter = require('events').EventEmitter;

class X extends EventEmitter{
    constructor(){
        super();
        setInterval(()=>{
            this.emit('newlesson',{
                price:Math.random()*100
            });
        },3000)
    }
}

const x = new X();
x.addListener('newlesson',(res)=>{
    console.log('buy!',res);
});

file

本文由博客群发一文多发等运营工具平台 OpenWrite 发布

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多