这是我参与「第四届青训营 」笔记创作活动的的第1天
使用平台:vscode(win端),chorme,node.js(v16.16.0.)\
1.发现问题
为了巩固在青训营中学到的js知识,我打算刷一些js算法题,但是在写题过程中我发现我的代码输入报错
var line = parseInt(readline());
ReferenceError: readline is not defined
查询论坛的文章发现,在我使用的VSCode编辑器中,安装的是node.js的运行环境,需要引用node中的readline模块实现控制台输入。
在加入:
import * as readline from 'node:readline';
后,直接作为.js文件的代码可以运行了,但是放在script标签中依旧报错
Uncaught SyntaxError: Cannot use import statement outside a module
2. 初步尝试
我发现在node.js的官方文档中,引用readline模块可以有CJS和ESM两种模式,ESM模式使用的是import语法。我又尝试了CJS模式的模块引用:
const readline = require('node:readline');
结果还是报错
Uncaught ReferenceError: require is not defined
一番尝试后,我发现为script标签的type属性指定为module后,ESM引用可以在浏览器中运行了,但是触发了同源策略的保护而报错...
3.分析问题
在尝试以上代码之前我甚至不知道CJS和ESM是什么,不过我现在知道了这是两种不同的模块体系。CJS是指CommonJS,是主要用于服务器端的一种同步加载的模块体系,而ESM即ESModule,是主要用于浏览器端的异步加载的模块体系。我还了解到ESM是ECMAScript自己的模块体系,难怪node.js官网默认的代码模式是ESM,大概是因为这种模式更官方?
ESM主要用于浏览器端,也可以解释为何我的浏览器(我用的是chorme)仅支持ESM模式的代码编译。
为了能顺利刷上题,我还是选择创建.js文件在编译器编译
在令人安心的编译器界面,CJS和ESM的模块引入方式都能顺利通过编译,只是ESM模式需要把原本这个文件的.js后缀改成.mjs,这是node环境的强制规定,不这么做的话报错也会提示。
模块引入后,创建readline.Interfance实例,再定义输入输出流: CJS的一种写法:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
ESM的一种写法:
import * as readline from 'node:readline';
import { stdin as input, stdout as output } from 'node:process';
const rl = readline.createInterface({ input, output });
都可以成功编译不报错。
process模块可以创建一个双向通讯流,连接到stdin时它是可读的,stdout则是可写的。(在官方文档的描述中还提到了fd0 fd1,似乎和系统的输入输出有关?)
4.应用发现
我想要获取一个字符串,再返回它与received:的拼串,以便查看是否成功获取:
let inputStr = '';
rl.on('line', function(line){
inputStr = line;
}).on('close', function(){
console.log('received: '+inputStr);
})
根据编译器的提示,on方法会传入一个event和一个listener,listener函数会加入到eventName名称的数组中,反复使用这个方法会重复添加和调用listener函数。一般情况下,事件的监听函数会以被添加的顺序唤起。
终于可以正常输入输出了...只是在终端输入后要enter一下再按ctrl+d结束,这是因为readline.Interfance使用stdin输入后,需要返回EOF终止。(注意!这里编译器的提示不一定对,编译器一直告诉我ctrl+d是linux/mac系统的EOF,ctrl+z才是我用的windows的,结果我摁了半天ctrl+z也没用...难道是因为我的win是win11吗?)
今天的报错排雷之旅就到这里了,感谢阅读~