前端工程化——Node.js - Go语言中文社区

前端工程化——Node.js


上一节讲述了前端工程化的概念,最后提到 Node.js 

因为前端工程化中大多数技术和工具都是基于Node.js 的 运行环境

为什么说是运行环境而不是编程语言?

        从官方网站(https://nodejs.org)中可以看到 

        Node.js® 是一个基于 Chrome V8引擎 的 JavaScript 运行时环境。

Chrome V8引擎是什么?JavaScript的运行时环境又是什么?想知道这两个答案,需要了解浏览器的组成

浏览器的组成,分为内核和外壳.

而内核的组成是由渲染引擎(可以理解为Html,Css)和 Js 引擎组成的.

V8 就是 Chrome中的Js引擎

而浏览器就是 JavaScript 运行环境其中之一。

这样Node.js 的概念也可以理解了,Node.js 也是 JavaScript 运行环境

下面就可以列举了各大主流浏览器的信息 和 软件架构图,以便于更好理解

 既然 Browser 和 Node.js 都是 JavaScript 运行环境,两者又有什么区别呢?

       Browser (JavaScript) —— Runtime

                处理浏览器响应事件

                处理交互效果

                数据校验

                不可以做文件的操作

        Node.js (JavaScript) —— Runtime

                可以开发桌面应用 例如 VsCode

                可以说网站、小程序、app 数据服务

                提供各种前端工程化的工具

Node.js 的基本概念和相关的基础知识点介绍完成了,正式学习Node.js 的 Api

Node.js API

        Node.js 是由 ECMAScriptNode.js APIs 组成

ECMAScript是什么呢?

        可以简单的理解成 JavaScript 是 ECMAScript 的扩展,ECMAScript 则是基础。

        所以 JavaScript 的基本语法也是可以在 Node.js 中使用的,

        有关 ECMAScript 的具体讲解,在Javascript章节讲解,这里不过多的展开解释

        Node.js Apis 是由一些模块在组成 .

什么是模块呢?

        Node.js 中模块的概念,相当于JavaScript 中的对象, 大部分前端工程化的工具,都是以模块化形式存在的。

当然使用 API 需要先安装 Node.js 安装步骤这边就不展开了,

直接官方网站,下载安装程序,直接安装,实在困难某度一下就好

安装好后 可以在命令窗口输入 ,如果显示版本号,则安装成功了

node --version

如何使用 Node.js?

        一种为脚本模式,一种为交互模式,。

        我就用是 vscdoe 开发应用举例说明两种模式

--脚本模式 script mode

// 创建一个 node.js 文件
console.log('hello Node.js')

// vscode 中使用 快捷键 Ctrl+` 进入命令行终端
> node .\node.js
hello Node.js
--交互模式

// vscode 中使用 快捷键 Ctrl+` 进入命令行
> node //进入交互模式
> console.log('hello Node.js') //Enter
hello Node.js

交互模式 Interactive mode

        使用 Tab 按键可以自动补全

        查看JavaScript对象(Math. 然后两下Tab)

        点命令 (.help)

相比于 Browser 的全局对象 Window , Node.js 也有全局对象 global

globa 全局对象在两种执行模式下,访问权限是不一样的。

在交互模式下 global 可以访问定义的变量,在脚本模式下是不可以的

scprit mode:
    // create node.js
    var a = 1;
    console.log(global.a)
    > node .\node.js
    > undefined
    
interactive mode:
    > node
    > var b = 2
    > console.log(global.b)
    > 2

有全局对象,也会有全局函数,JavaScript中的全局函数,在Node.js下也可以使用

        例 一些定时函数 (setTimeout / clearTimeout) (setInterval / clearInterval)

        还有一些转换函数 ( parseInt / parseFloat /isNaN ...)

Node.js 环境也提供了一些全局函数

        setImmediate / clearImmediate 立即执行器

        process.nextTick 进程立即执行器

来通过代码来了解一下

//create global_func.js
var flo = 1.23456789;
console.log(parseInt(flo));

var timer = setTimeout(() =>{
    console.log(2)
},100)

setImmediate(() => {
    console.log(5)
})

> node .\global_func.js
> 1
> 5
> 2

为什么执行顺序不是 1,2,5 而是 1,5,2 ? 想知道这个执行顺序,必须了解同步和异步

        首先我们要知道 Js 的运行是一种自上而下的顺序,是单线程来执行的。

        如果第一个任务执行的时间很长,第二个任务会一直等待,也叫处于阻塞状态。

        很显然这有很大的弊端,而这就是同步执行。

        异步呢,假如第一个任务执行时间很长,在 Js 中可以交给事件队列去执行,

        这样第二个任务,不必等待第一个任务处理完才能执行。

那交给事件队列执行的任务何时执行呢?

         等到所有主程序中的任务全部执行完,才可以执行,

        setImmediate() 函数 就是在 事件队列的最顶端

        setTimeout() 函数 在事件队列中

说到了 setImmediate() 不得不说 prcocess.nextTick() 函数这两者有什么不一样呢?        

        setImmediate() 叫做立即性执行函数

        prcocess.nextTick() 叫做 进程立即执行函数,process 也是个全局变量

        区别除了名称不同,执行的顺序也不同,

        process.nextTick() 是在主程序执行完成之后立即执行,

        setImmediate() 是在事件队列最顶端执行

        补充一下上面代码 便于理解

// global_func.js
// Add function after setimmediate()
process.nextTick(() =>{
    console.log(7)
})

> node .\global_func.js
> 1
> 7
> 5
> 2

 Node.js 模块

        模块(包)是Node.js 应用程序的基本组成部分,也是特定功能的对象

        Node.js 可以大致分为 内置模块 、自定义模块 、第三方模块。

        根据这三部分内容来逐一学习各个模块内基础的 api

内置模块

        也叫核心模块,跟随 Node.js 一起安装 http://nodejs.cn.api

核心模块 —— console

        控制台输出的内容的一个模块,也是全局对象,下面常用的方法

// create console.js

let a = 1;
let str = '加油,成为自己的理想型';

const obj = {
    name : 'Simon',
    age : 28
};

console.log(a);
console.log(str);
console.log(obj);
console.table(obj);  // 以表格的形式输出

//计时
console.time('for')
    for (let i =0;i<1000000 ;i ++){

    }
console.timeEnd('for')

console.time('while')
let j = 0
  while( j < 1000000){
    j++
  }
console.timeEnd('while')

> node .\console.js
1
加油,成为自己的理想型
{ name: 'Simon', age: 28 }
┌─────────┬─────────┐
│ (index) │ Values  │
├─────────┼─────────┤
│  name   │ 'Simon' │
│   age   │   28    │
└─────────┴─────────┘
for: 3.539ms
while: 2.083ms

// 有一点注意同样是循环 1000000次 while循环要比 for循环 快

核心模块——process

        process 提供了所有 Node.js进程信息 process也是全局变量

//create process.js
// 输出 node 版本
console.log(process.version)

// 输出操作系统架构
console.log(process.arch)

// 输出操作系统平台
console.log(process.platform)

// 输出当前工作目录 cwd = current working directory
console.log(process.cwd())

// 环境变量
console.log(process.env)
// 自定义环境变量
process.env.NODE_ENV = 'develop'
console.log(process.env)

// 获取进程的编号
console.log(process.pid)

// 杀死进程  process.kill(pid)

核心模块——path

        path 模块是操作路径的函数,并不是全局对象,需要require来引入

const path = require('path')

//获取工作目录
console.log(process.cwd())
// 获取工作目录
console.log(__dirname)
// 获取文件中的目录部分
console.log(path.dirname(__filename))

// 获取文件完整的路径
console.log(__filename)

// 获取文件名称
console.log(path.basename(__filename))

// 获取文件的拓展名 extension = ext
console.log(path.extname(__filename))

// 拼接路径方法
console.log(path.join(__dirname,'1.txt'))

核心模块——fs

        fs (file system) 提供了文件操作的api,需要通过require导入

                文件操作

                目录操作

        文件操作,写入,读取,追加,删除

const fs = require('fs')

const path = __dirname + '/src'
let content = '我想活出自己的理想型,只为和她并肩而行'

//writeFile(path , content , callback(err))  每次写入文件都是清空后写入
fs.writeFile(path + '/hope.txt', content ,(err) => {
    if (err) throw err
    console.log('write success....')
})

//readFile(path , callback(err,data)) read file
fs.readFile(path + '/hope.txt',(err,data) => {
    if (err) throw err
    console.log('read hope:' + data)
})

//appendFile(path,content,callback(err)) 追加写入,不清空原有数据
let content_append = '我知道她对于我来说是遥不可及,可是我就是想靠近,想拼命的靠近'
fs.appendFile(path + '/hope.txt' ,'\n'+ content_append , (err) => {
    if (err) throw err
    console.log('append write success....')
})

// unlink(path , callback(err)) delete file
fs.unlink(path + '/hope.txt', (err) => {
    if (err) throw err
    console.log('delete success.....')
})

        目录操作 创建、重命名、读取、删除

const fs = require('fs')
const path = require('path')

const cwd = __dirname;
const dir_name = 'dist';
const path_ = path.join(cwd ,dir_name)

//mkdir(path, callback(err))
fs.mkdir(path_ , (err) => {
    if(err) throw err
    console.log('create dir success .....')
})

//rename( old_path_name, new_path_name, callback(err))
fs.rename(path_ + '/yueyue', path_+ '/J.W' ,(err) =>{
    if(err) throw err
    console.log('modify dir success ...')
})

// 删除目录,只能删除空目录,该目录下不可以有文件,要想删除清空文件后,继续删除
// rmdir(path , callback(err))
fs.rmdir(path_+ '/J.W' , (err) => {
    if(err) throw err
    console.log('delete dir success....')
})

// 读取目录 readdir(path , callback(err,data))
fs.readdir(path_, (err,data) => {
    if (err) throw err
    data.map((d) =>{
        // 读取文件信息 stat(path , callback(err,stat))
        fs.stat(path_ + '/' + d, (err,stat) => {
            if (err) throw err
                if(stat.isDirectory()) {
                    console.log('> ' + d)
                }else if(stat.isFile()) {
                    console.log(d)
                }
        })
    })
})

        fs——同步操作

                fs的同步操作,需要注意的就是场景应用。

                比如,要确保文件是否存在,如果存在,在进行删除操作

                这样需要有顺序的执行,可以用到同步函数

                文件操作的同步函数,没有callback

const fs = require('fs')

const path_ = __dirname + '/love.txt'

if(fs.existsSync(path_)){
    fs.unlinkSync(path_)
}else{
    console.log('file does not exist ...')
}

        fs 文件操作 缓冲vs流

                文件操作有两种模式 第一种 内存缓冲

                复制文件的过程中,会把源文件加载到内存中,再从内存中读取到目标文件中

                如果文件很大,也会往内存中加载,这种加载模式 有一定的弊端

 

        两种模式,为什么建议用 ‘流’ 模式?

                内存不需要加载大量数据 内存效率高

                接取数据后立即开始处理 时间效率高

const fs = require('fs')
//获取读取流
var readStream = fs.createReadStream(__dirname + '/src/hope.txt')
// 获取写入流
var writeStream = fs.createWriteStream(__dirname + '/love.txt')

// 读取流通过管道写入文件内容
readStream.pipe(writeStream)

核心模块——http

        http 可以发布web服务,需要引入require

const http = require('http')

// 创建服务器   req = request 请求 res = response 响应
const server = http.createServer((req,res) => {
    res.statusCode = 200;
    res.setHeader('Content-Type' ,'text/plain; charset=utf-8')
    res.end('http core module')
})

// 发布服务
const port = 8089;   //端口号
const host = 'localhost';  //域名

//server.listen(port , host ,callback)
server.listen(port, host, () => {
    console.log(`服务器运行在 http://${host}:${port}`)
})

对于前端工程化要使用node.js的内置模块已了解大概了

自定义模块

        node.js 中每一个 js 都是一个单独的模块 , 每个模块中都有一个module的变量

        我们可以打印一下

// create circle.js
console.log(mudule)

> node .\circle.js
Module {
  id: '.',
  path: 'D:\\Software\\vscode\\web_workspace\\Node_Practise_01',
  exports: {},
  parent: null,
  filename: 'D:\\Software\\vscode\\web_workspace\\Node_Practise_01\\circle.js',
  loaded: false,
  children: [],
  paths: [
    'D:\\Software\\vscode\\web_workspace\\Node_Practise_01\\node_modules',
    'D:\\Software\\vscode\\web_workspace\\node_modules',
    'D:\\Software\\vscode\\node_modules',
    'D:\\Software\\node_modules',
    'D:\\node_modules'
  ]
}

        每一个module对象都有exports 属性,使用这个属性就可以被外部调用

// append circle
const PI = 3.14;
// 计算周长
const perimeter = (r) => {
    return 2 * PI * r
}

// 计算面积
const area = (r) => {
    return PI * Math.pow(r,2)
}

// 模块中的属性或方法,必须导出,然后才能被使用
module.exports = {
    perimeter,
    area
}

// create app.js
const circle = require('./circle') //自定义模块导入需要完整路径
const r = 55;
console.log(circle.perimeter(r))
console.log(circle.area(r))

模块的加载逻辑

        按组织方式划分模块,分为文件模块,目录模块

         文件的加载逻辑

// 1.引入自定义模块 要写完成路径
const circle = require('./circle')

// 2.引入内置模块 不需要写路径
const path = require('path')

        目录加载逻辑

                1.指定路径开头 require('./dir01') , 会进入指定目录,找入口文件

                2.不指定路径开头 require('dir01'),

                会从该目录下找node_modules文件夹下的目录dir01.然后再寻找入口文件

                如果找不到会到上一级,知道顶层目录

                如何寻找入口文件呢?

                如果文件夹中没有package.json文件,默认引入index.js,

                如果存在该文件入口文件通过其中的 main 属性指定

//1.指定路径开头

//create mkdir dir01
// > dir01 create index.js

function info(){
    console.log('要在这世俗的雨里,决定成为自己 index.js')
}
module.exports ={
    info
}

// creare execute.js
const dir01 = require('./dir01')
console.log(dir01.info())

> node .\execute.js
要在这世俗的雨里,决定成为自己 index.js
// 2.不指定路径开头
// create mkdir node_modules > dir01
// create dir.js , dir01_a.js, dir01_b.js package.json

//dir.js
const a = require('./dir01_a')
const b = require('./dir01_b')

function info(){
    console.log('要在这世俗的雨里,决定成为自己 dir.js')
    a.info()
    b.info()
}
module.exports ={
    info
}

//dir01_a.js
function info(){
    console.log('今天我有离你进了一步 我是A.js')
}
module.exports = {
    info
}

// dir01_b.js
function info(){
    console.log('我想离你近一些 我是B.js')
}
module.exports = {
    info
}

// package.json
{
    "main" : "./dir.js"
}

// execute.js
const dir01 = require('dir01')
console.log(dir01.info())

> node .\execute.js
要在这世俗的雨里,决定成为自己 dir.js
今天我有离你进了一步 我是A.js
我想离你近一些 我是B.js

第三方模块

        前端工程化大部分都是第三方模块,要使用第三方模块,需要使用 node.js 安装

npmhttps://www.npmjs.com/

        npm是什么呢?

        npm 是 node.js 的包的管理工具。那包又是什么?

                包就是 Node.js 的第三方模块

        npm 随着 node.js 安装一起安装,所以不用单独安装

        通过 npm 安装包的好处是什么呢?

                npm 不仅是可以安装想要的包,还可以安装它的依赖

                比如 : 安装Bootstrap 通过 npm 命令安装

                不仅可以安装 BootStrap 还可以安装它的依赖 jQuery

        那如何使用npm安装包呢?

npm install <package-name>

        安装包的方式也有两种: 一种是全局安装,一种是项目安装

//全局安装
> npm install <package-name> --global
or
> npm i <package-name> -g

// 例如安装 yarn 
npm i yarn -g
//项目安装
> mkdir project 
> cd project
> npm init --yes
// 在项目中安装包

        项目中安装的包 也有区分,一种是开发环境所用,一种是开发上线环境都要使用

// 开发上线环境都要使用 例 jQuery
> npm i <package-name> --save
or
> npm i <package-name> -S
//开发环境才使用 例minify
> npm i <package-name> --save-dev
or
> npm i <package-name> -D

与前端工程化相关的 node.js 基础已经介绍完成,下一章节,介绍脚手架工具

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_38688197/article/details/126247351
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2023-01-02 21:18:50
  • 阅读 ( 60 )
  • 分类:前端

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢