第一章:node的介绍及安装
1.node介绍与安装:
node是一个基于V8引擎之上的一个JavaScript运行环境 他使得JavaScript可以运行在浏览器以外的地方 相对于大部分的服务器端语言来说 node有很大的不同 他采用了单线程 且通过异步的方式来处理并发问题
node.js:运行在服务器端的js
用来编写服务器
特点:单线程 异步 非阻塞
统一API
2.安装: 浏览器搜索node下载安装
使用安装工具nvm来进行安装
以管理员模式运行终端 在终端输入nvm version 查看版本号 出现版本号就说明安装成功了
常见的nvm 命令:
---nvm list 查看当前安装的node版本
--nvm install 版本号 安装指定版本的node
安装nvm的时候先配置一下nvm的镜像服务器
终端输入: nvm node_mirror https://npmmirror.com/mirrors/node/
终端输入 npm install latest
下载完成后 执行 nvm use 版本号 --指定要使用的node版本
3.node的使用:
1.在终端使用js的代码语法
2.在开发工具里面使用工具自带的终端
node,js和JavaScript有什么区别:
ECMScript DOM BOM
第二章:同步和异步
/*进程和线程:
* --进程(厂房):
* 程序运行的环境
* --线程(工人):
* 实际进行运算的东西
*
* 同步:--通常情况下代码都是自上而下一行一行的执行的 前面的代码不执行后面的代码也不会执行
* 同步的代码执行会出现阻塞情况
*
* 因此同步会出现 : 一行代码执行慢会影响到整个程序的执行
*
*
* 解决同步问题:
* --- Java Python 这些是通过多线程来解决 编写程序去管理 比较麻烦
* node.js:单线程的:
* ----通过异步的方式来解决
* 异步: 一段代码的执行不会影响到其他代码的执行
* */
console.log("哈哈")
console.log("嘻嘻")
console.log("嘿嘿")
//以上代码就按照顺序来执行 的 第一个没有执行 第二个也不会执行
//例如:同步
function f(a,b) {
return a+b;
}
//异步:
function f1(a,b,cd) {
setTimeout(()=>{
cd(a+b)
},1000)//10000 毫秒执行这个代码块
}
//因此使用回调函数来返回运算结果
const x=f1(666,777,(x)=>{
console.log(x)
});
/*异步的代码无法通过return来设置返回值 */
// console.log("我是延时后的代码",x);
const r=f(1,3);
console.log(r);
/*基于回调函数的异步带来的问题:
* 1.代码的可读性差
* 2.可调试性差
*
* 解决方法:因此需要一个东西:可以代替回调函数来给我们返回结果
* 因此使用Promise就出现:可以用来存储数据的对象 Promise存储数据的方式比较特殊 这种特殊方式使得promise可以用来存储
* 异步调用的数据
*
* */
第三章:Promise介绍
function f(a,b,cd) {
// 调用cd函数
cd(a+b)
}
f(123,456,function (result) {
console.log("你好 我是cd函数")
console.log(result)
})
//以上就异步编程
/*因为异步调用必须通过回调函数来返回数据:当我们进行一些复杂的调用时 会出现“回调地狱”
* 问题:异步必须通过回调函数来返回结果 回调函数一朵就会很痛苦
*
* promise:可以帮助我们解决异步中的回调函数的问题
* promise就是一个用来存储数据的容器 这个方式使得它里面可以存储异步调用的结果
*
* */
//一.promise的使用
//1.创建promise
//创建promise时 构造函数需要用一个函数作为参数
//promise构造函数的回调函数 他会在创建promise时调用 调用时会有两个参数传递进去
const promise=new Promise((resolve,reject)=>{
//resolve和reject是两个函数 通过这个函数可以向promise中存储数据
console.log("回调函数执行了")
// resolve在执行正常的时候 存储数据 reject在执行错误的时候存储数据
console.log(resolve,reject)
// 通过函数来向promise中添加数据 好处就是可以用来添加异步调用的数据
})
console.log(promise);
/*读取数据:
* 从promise中读取数据:可以通过promise的实例方法then来读取Promise中存储的数据---注意:需要使用回调函数作为参数
*
* then()需要两个回调函数作为参数 回调函数用来获取Promise中的数据
* 通过resolve存储的数据 会调用第一个函数返回
* 通过reject存储的数据或者出现一次时 会调用第二个函数返回
* 因此可以在第二个函数中编写处理异常的代码
*
* */
promise.then((result)=>{
console.log("promise中的数据",result)
},(reason)=>{
console.log("2",reason)
})
/*promise的原理:
*
* Promise中维护了两个隐藏的属性:
* promiseResult:用来存储数据 ,对于异步来说
*
* PromiseState:--记录promise的状态(三种状态:完成(fulfilled):通过resolve存储数据时
* ,拒绝(rejected):出错了 或通过reject存储数据时
*
* ,正在进行中(padding))
* ----state只能修改因此 修改以后就永远不会在变
*
* 流程:当Promise创建时 promisesState初始值为padding:当通过resolve存储数据时,PromiseState 变为fulfilled(完成)
* promiseResult变为存储的数据
*
*
* 当通过resolve存储数据时,PromiseState 变为rejected(拒绝,出错了)
* promiseResult变为存储的数据 或异常对象
* 当我们通过then在读取数据 相对于为promise设置了回调函数 如果PromiseState变为fulfilled 则调用then的第一个回调函数返回数据
* 如果PromiseState变为Reject 则调用then的第二个回调函数来进行处理
*
*
* */
const promise2=new Promise((resolve,reject)=>{
resolve("你好")
})
console.log(promise2)
/*catch()的用法和then类似 但是只是需要一个回调函数作为参数
* catch()中的回调函数只会在Promise被拒绝的时候才会被调用
* catch()相对于 then(null,reason=>{})
* catch()就是一个专门处理Promise异常的方法
*
* finally()--无论是正常存储数据还是异常了 finally总会执行 但是finally的回调函数中不会接收到数据
* finally()通常用来编写一些无论成功与否都要执行代码
* */
promise2.catch(reason => {
console.log(123)
})
promise2.finally(()=>{
console.log()
})
/*
* promise1:就是一个用来存储数据对象
* 但是由于Promise存取的方式的特殊 因此可以直接将异步调用的结果存储到Promise中
* */
const promise=new Promise((resolve, reject)=>{
resolve("我存取了数据 通过resolve来存储")
})
//取出数据
/*
promise.then(result=>{
console.log(result)
},reason =>
{
console.log("出错了",reason)
}
)*/
function sum(a,b){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(a+b)//把异步的结果存进去
},1000)
})
}
//拿到结果后 丢啊哦用then方法 取出数据
sum(123,456).then(result=>{
console.log(result)
sum(result,234).then(result=>{
sum(result,789).then(result=>{
sum(result,4567).then(result=>{
sum(result,8876).then(result=>{
console.log(result)
})
})
})
})
})
/*promise中的:then(return new Promise())
catch
finally 中三个方法都会返回一个新的Promise
* Promise中会存储回调函数的返回值
* finally的返回值 不会存储到新的Promise中
* */
const p2=promise.then(
result=>{
console.log("回调函数",result)
return "锄禾日当午!"
}
)
p2.then(result=>{
console.log(result)
})
console.log(p2)
/*
promise.then(result=>{
console.log("第一个",result)
return "你好!"
}).then(result=>{
console.log("第二个",result)
}).then(result=>{
console.log("第三个",result)
})*/
//优化版的求和:
sum(123,456)
.then(result=>result+7)
.then(result=> result+8)
.then(result=> console.log(result));
//异常;
promise
.then(r=> "哈哈")
.catch(r=>{
throw new Error("报错")
return "报错完毕!"
})
.then(r=> {
//如果出现异常 那么久阿婆出异常
console.log("第二个then",r)
return "整个异常已经抛出"
})
//后面的方法读取的是前一个方法的结果 then和catch 读取上一步的执行结果
// 如果上一步的执行结果不是当前想要的结果 则跳过当前的方法
//当promise 出现异常的时,整个调用链中没有出现catch 则异常会向外抛出
/*
* 静态方法:
Promise.resolve(10) 创建一个立即
*
*
* 完成的Promise
*
* */
Promise.resolve(10).then(r=>console.log(r))
// Promise.reject() 创建一个立即拒绝的promise
function f(a,b) {
return new Promise(((resolve, reject) => {
setTimeout(()=>{
resolve(a+b)
},1000)
}))
}
Promise.all([sum(123,34),
sum(234,678),
sum(789,99)
]).then(r=>{
console.log(r)
})
//Promise.all方法同时返回数组
//这个方法有一个报错整个报错
//Promise.allSettled 这个方法会返回所有数组
Promise.allSettled([sum(123,899),
sum(278,998),
sum(234,6655)
]).then(r=>{
console.log(r)
})
//Promise.race([。。。]) 这个方法返回执行最快的Promise 不报错
Promise.race([
sum(123,456),
sum(373,448),
sum(2344,66)
]).then(r=>{
console.log(r)
})
//amy 都报错才会整体报错
Promise.any([
sum(123,67),
sum(233,45),
sum(234,344)
]).then(r=> {
console.log(r)
})
第四章:宏任务和微任务
/*
* js代码是单线程 同一个时间内只能做一件事情 他的运行时基于循环机制(event loop)
*
* 调用栈:
* 栈;是一种数据结构 后进先出 调用栈栈放的是要执行的代码
* --任务队列:
* --队列:队列是一种数据结构 先进先出
* 任务队列是将要执行的代码
* 当调用栈中的代码执行完毕后 队列中的代码才会按照顺序一次进入到栈栈执行
* --在js栈任务队列有两种 :--1.宏任务队列(大部分代码都会去宏任务队列中去排队)
* --2.微任务队列 (Promise的回调函数(then catch finally))
* 整个流程:1.执行调用栈栈的代码啊===>2执行微任务队列栈的所有任务===>3.执行宏任务中的所有任务
*
* */
//定时器的作用就是:间隔一段时间后 将函数放入到任务队列中 进行排队 排队等待
/*
//例如:创建一个r 并且读取其中的内容 这个语句就是把1234存储进去 然后再通过than来读取出来
Promise.resolve(1234).then(r=>{
console.log(r)
})
*/
/*Promise执行原理:在Promise在执行 then就相当于给Promise了回调函数 当Promise的状态从pending变为
* fulfilled时 then的回调函数就会被放入到任务队列中
*
*
* */
//例如:下面两个语句那个先执行
/*setTimeout(()=>{
console.log("5秒后出现")
},5000)*/
// console.log(456)
//微任务队列函数:queueMicrotask(()=>{}) 作用就是用来向微任务中添加一个任务
queueMicrotask(()=>{
console.log("1.微任务!")
})
console.log("2.宏任务")
Promise.resolve().then(()=>{
console.log("3.微任务立即执行")
})
//手写Promise:
//定义累的思路: 1.先把功能分析清楚 在动手 2.写一点想一点 走一步看异步
// 第一步:创建一个类:
class MyPromise{
//创建一个变量用来存储Promise的结果
#result
//创建一个变量来记录Promise的状态
#state=0 //padding 0 fulfilled 1 rejected 2
constructor(executor) {
//接收一个执行器 作为参数
// 使用bind()方法 可以绑定当前的this
executor(this.#resolve.bind(this),this.#reject.bind(this))//调用回调函数 并且拿到当前参数 传递进去
}
//私有的resolve()用来存储成功的数据
/*
方式一:
#resolve(value){
console.log("resolve被调用了 value值是:",value)
// console.log(this) 不能使用this来定义 整个最后输出的结果是undefined
}
*/
//方式二:
#resolve=(value)=>{
// console.log(this) 输出MyPromise {} 整个是可以的
// 禁止值被重复修改:
if (this.#state!==0){//如果state不等于0 说明值已经被修改 函数直接返回
return
}
this.#result=value
this.#state=1 //整个表示数据添加成功
}
//私有的reject()用来存储拒绝的数据
#reject(reason){}
// 添加一个用来读取数据的then方法
then(onFulFilled,onRejected){
// 两个参数 成功的时候一个状态 失败的时候一个状态
if (this.#state===1){
onFulFilled(this.#result)
}
}
}
const mp=new MyPromise((resolve,reject)=>{
resolve("存取数据了 无懈")
resolve("无邪")
resolve("解雨臣")
console.log("回调函数执行了!!!")
})
console.log(mp)
mp.then((result)=>{
console.log("读取数据",result)
})
手写Promise的原理:
//手写Promise:
//定义累的思路: 1.先把功能分析清楚 在动手 2.写一点想一点 走一步看异步
// 第一步:创建一个类:
class MyPromise{
//创建一个变量用来存储Promise的结果
#result
//创建一个变量来记录Promise的状态
#state=0 //padding 0 fulfilled 1 rejected 2
//创建一个变量来记录Promise的状态
#callback
constructor(executor) {
//接收一个执行器 作为参数
// 使用bind()方法 可以绑定当前的this
executor(this.#resolve.bind(this),this.#reject.bind(this))//调用回调函数 并且拿到当前参数 传递进去
}
//私有的resolve()用来存储成功的数据
/*
方式一:
#resolve(value){
console.log("resolve被调用了 value值是:",value)
// console.log(this) 不能使用this来定义 整个最后输出的结果是undefined
}
*/
//方式二:
#resolve=(value)=>{
// console.log(this) 输出MyPromise {} 整个是可以的
// 禁止值被重复修改:
if (this.#state!==0){//如果state不等于0 说明值已经被修改 函数直接返回
return
}
this.#result=value
this.#state=1 //整个表示数据添加成功
// 单resolve执行时 说明数据已经进来了 需要调用then的回调函数
this.#callback(this.#result)
}
//私有的reject()用来存储拒绝的数据
#reject(reason){}
// 添加一个用来读取数据的then方法
then(onFulFilled,onRejected){
// 两个参数 成功的时候一个状态 失败的时候一个状态
/*
*目前来说:then只能读取到已经存储到Promise的数据 而不能读取到异步存储的数据
*
* */
if (this.#state===1){
// 进入判断说明数据还没有进入到Promise 将回调函数设置为callback
this.#callback=onFulFilled
}
if (this.#state===1){
onFulFilled(this.#result)
}
}
}
const mp=new MyPromise((resolve,reject)=>{
resolve("存取数据了 无懈")
resolve("无邪")
resolve("解雨臣")
console.log("回调函数执行了!!!")
})
console.log(mp)
mp.then((result)=>{
console.log("读取数据",result)
})
第五章:规范化
1.规范化
/*
*
* async:通过这个可以快速的创建异步函数
*
* */
/*
function f() {
return Promise.resolve(10)
}
*/
/*
* 通过async创建的异步函数:异步函数的返回值会自动封装到Promise中返回
* 在async声明的异步函数中可以使用 await关键字来调用异步函数
* */
/*
async function f1() {
return 10
}
f().then(r=>{
console.log(r)
})
let result =f1()
console.log(result)*/
function f1(a,b) {
return new Promise(resolve => {
setTimeout(()=>{
resolve(a+b)
},5000)
})
}
async function f2() {
// 在这个代码块里面调用
/*f1(123,455).then(r=>{
console.log(r)
})*/
//当我们通过await去调用异步函数时 他会暂停代码的运行 直到异步代码的运行结果时候 才会将结果返回
//注意:await只能用于async声明的异步函数中 或es模块的顶级作用域中
let result= await f1(123,234)
console.log(result)
try {//通过await调用异步代码时 需要通过try---catch来处理异常
result = await f1(result,56)
result=await f1(result,678)
console.log(result)
}catch (e)
{
console.log("出错了!")
}
}
f2()
console.log("全局输出!")
// await 阻塞的是异步函数内部的代码 不会影响外部代码
/*Promise 解决了异步调用中回调函数的问题 但是链式调用太多以后还是不好看
* 通过同步的方式调用异步代码 await的使用
* */
//如果async中声明的函数中没有写await 那么里面的代码就会依次执行
/*
* 当使用await调用函数后 当前函数后面的所有代码会在当前函数执行完毕后 被放入微任务队列里面
*
* */
2.CommonJS规范
/*1.模块化:
* 随着学习的深入 各种功能越来越复杂 因此不易于维护 所以把整个代码 拆分为一个个小版块
*
* 早期的网页中是没有一个实质的模块化规范的 实现实质化
*
* 1.无法选择要引入模块的那些内容
* 2.在复杂的模块化场景下非常容易出错
*
* 于是就需要在js中引入一个模块化的解决方案
*
* 在node中 默认支持的模块化规范叫做CommonJS 在CommonJS中 一个js文件就是一个模块
*
* CommonJS规范:
* ---引入模块
* 使用require()函数来引入模块
* ---引入自定义模块的时候 模块名要以./或../开头 扩展名可以省略不写
* 在CommonJS中 如果省略了扩展名 node会自动补全扩展名
* 先找js ---->json--->node(特殊)
*
*
* 引入核心模块时:直接写核心模块即可
*
*
* 在定义模块时 模块中的内容默认是不能被外部考到的 可以通过exports来设置暴露的内容
*
* 访问exports的方式有两种:
* exports
* module.exports
*
* 当我们在其他模块中引入当前模块时 require函数返回的就是exports
* 可以将希望暴露给外部模块的内容设置为exports的属性
* */
//使用require()引入:
/*
const m1= require("./03.Promise进阶")
console.log(m1);
*/
/*console.log(exports);
console.log(module.exports)*/
//也可以向外部暴露特定的值:
/*
exports.a="无邪"
exports.b="解雨臣"
*/
//也可以直接通过module.exports同时到处多个值
/*
module.exports={
a:"哈哈哈",
b:"你哈",
c:()=>{
console.log("你好 风轻云淡")
}
}
*/
//比如引入node里面自带的path模块:也可以在核心模块前添加 node:path
const path=require("path")
console.log(path)
/*默认情况下:node会将以下内容视为CommonJS模块
* 1.使用.cjs为扩展名的文件
* 2.当前package,json 的type属性为CommonJS时 扩展名为.js的文件
* 3.当前package.json不包含type属性时 扩展名为.js的文件
* 4.文件扩展名为mjs cjs json node js 以外的值时 (type不是module时)
*
*
* 使用文件夹作为模块也是如此
*
* */
//原理:module exports
//所有的CommonJS的模块都活包装在英国函数中
3.ES模块化规范
module.exports={
name:"无邪",
age:18,
gender:"男"
}
/*
* ES模块化:
*
*
* */
//向外部导出内容:
export let a=10
export let b="无邪"
console.log("无邪")
//默认导出
export default function f(a,b) {
return a+b
}
//导出对象:
// export default let d=20 这个是错误的
//引入模块(整体引入)
/*
const obj=require("./m3")
console.log(obj)
//局部 引入
const name=require("./m3").name
console.log(name)
const gender=require("./m3").gender
console.log(gender)
*/
/*
* 默认情况下 node中的模块化 标准是CommonJS
* 要想使用ES的模块化 可以采用以下两种
* 1.使用mjs作为扩展名
* 2.直接修改package.json将模块化规范设置为ES模块 "type": "module" 当我们设置了这个东西 当前项目下所有的js文件
* 都默认es module
*
*
* */
//导入m4,模块 es自定义模块不能省略扩展名(官方工具)
//改名称语法:通过as来起别名
import { a as hello} from "./m4.js"
console.log(hello)
import {a,b} from "./m4.js"
console.log(a);
console.log(b);
//第三种:导入全部
import * as m4 from "./m4"
console.log(m4.a)
//导入模块的默认导出
//默认导出的内容 可以随意起名 一个模块中只能有一个默认导出
import f from "./m4.js"
console.log(f)
//es模块都是运行在严格模式下
//Es模块化在浏览器中同样支持 但是通常我们不会直接使用
//通常会结合打包工具使用
4.process
11节