git、axios、模块化导出引入、promise、webpack、

GIT总结

git、axios、模块化导出引入、promise、webpack、_第1张图片
git config --global user.name "你的用户名"
git config --global user.email "你的邮箱"
git config -l 命令来查看配置信息
git init 仓库初始化
touch index.html 创建index.html文件
git add index.html 文件加入暂存区
git add -A 将全部文件加入暂存区
git commit -m '注释' 文件提交到本地仓库
ls 查看文件夹下的文件
git ls-file暂存区中的文件列表
clearctrl + l 清屏
mkdir 创建文件夹
rm test.html 删除工作区中的文件
git rm --cache 文件名 删除暂存区中的文件
git rm -f 文件名 同时删除暂存区和工作区中的文件
git rm 文件夹1 文件夹2 -r --cache 删除暂存区中的文件夹
git rm -r -f 文件夹名(git rm -f -r 文件夹名)同时删除暂存区和工作区中的文件夹:
cat test.html 查看文件内容
git status 版本状态查看
git log --查看提交日志
git log --oneline 以一行简化的方式查看
git reset --hard 版本号 进行版本回退
git branch name 创建分支
git checkout name 切换分支
git merge name1 name2 合并分支
git branch -d name1 name2 删除分支
git checkout -b name 创建并切换分支
git clone 克隆远程仓库
git remote add 别名 远程仓库地址 本地配置远程仓库的地址,并将本地仓库内容推送到远程仓库
git push -u 别名 分支名(默认是master)-u 关联(长链接), 加上以后,后续提交时可以直接使用 git push
git remote remove 别名 别名可以添加,也可以删除
git remote 该命令是查看远程仓库别名
git push :将本地仓库的 某个分支 推送到远端仓库的 某个分支
git pull 拉取代码

配置忽略文件
Git中需要创建一个文件【.gitignore】配置忽略

git分段拉取代码
git config core.sparsecheckout true
echo ‘day19’ >>.git/info/sparse-checkout
git pull origin master
git、axios、模块化导出引入、promise、webpack、_第2张图片

Axios

1.ajax请求的请求体数据格式

  • 当请求体数据为字符串时

    post请求体数据格式字符串:参数名=参数值&参数名=参数值…
    需要设置请求头
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    建立一个请求体格式的字符串
    let str = "user=admin&pass=123456" ;
    发送请求体数据
    xhr.send(str)

    服务端需要设置字符串请求头解析

    解析请求体数据格式
    这句话解析的请求体格式:参数名=参数值&参数名=参数值
    解析的请求头:application/x-www-form-urlencoded
    app.use(bodyParser.urlencoded({ extended: false }));

  • 当请求体数据为对象时

post请求数据格式字符串:也可以是JSON类型的字符串 ‘{“user”:“admin”,“pass”:“123456”}’
对应JSON类型格式数据的请求头:application/json
xhr.setRequestHeader('Content-Type', 'application/json');
这个JSON对象的键名就是将来服务端要获取的请求体对象中的键名
let obj = { user:admin , pass:123456 }
将JSON对象转换成JSON字符串
let str = JSON.stringify(obj);
将JSON字符串放到send中作为请求体数据
xhr.send(str);

服务端需要设置JSON字符串请求头解析

这句话解析的请求体格式:‘{“user”:“admin”,“pass”:“123456”}’ JSON类型的字符串
解析的请求头:application/json
app.use(bodyParser.json())

2.axios

2.1.axios基本使用

get

axios({
      //配置对象

       //1、请求方式
       method: 'get',

       //2、请求url
       url: "http://bj0313.com/getserver",

       //3、请求字符串
       params: {
           id: 1,
           user: 'admin'
       },

       //4、请求头
       headers: {
           x: 1,
           y: 2
       }
   }).then(value => {
       //value都包含
       /*  
       config:(axios中的配置对象--开发中需要的,咱们程序员用不到)
       data:响应体数据
       request:原生的ajax请求对象
       headers:响应头
       status:响应状态码
       statusText:响应状态文本字符串
       */
       console.log(value)
   })

post、put、patch、deletes

post、put、patch、deletes的方法参数都一致
data的传参方式不一样
data传参方式可以是对象也可以是字符串的方式
delete方法只能只用对象方法传入data,不能用字符串的方法

function post() {
      axios({
        method: 'post',
        url: "http://localhost:8080/login",
        params: {
          id: 12,
          name: '瑶瑶'
        },
        headers: {
          a: 1,
          b: 2
        },
        // data: {
        //   accont: '141546154',
        //   pwd: 123456
        // }
        data: `accont=141546154&pwd=123456`  //data传参方式可以是对象也可以是字符串的方式
      }).then(res => {
        console.log(res)
      })
    }

    function put() {
      axios({
        method: 'put',
        url: "http://localhost:8080/userput",
        params: {
          id: 12,
          name: '瑶瑶'
        },
        headers: {
          a: 1,
          b: 2
        },
        // data: {
        //   accont: '141546154',
        //   pwd: 123456
        // }
        data: `accont=141546154&pwd=123456`//data传参方式可以是对象也可以是字符串的方式
      }).then(res => {
        console.log(res)
      })
    }

    function patch() {
      axios({
        method: 'patch',
        url: "http://localhost:8080/userpatch",
        params: {
          id: 12,
          name: '瑶瑶'
        },
        headers: {
          a: 1,
          b: 2
        },
        // data: {
        //   accont: '141546154',
        //   pwd: 123456
        // }
        data: `accont=141546154&pwd=123456`//data传参方式可以是对象也可以是字符串的方式
      }).then(res => {
        console.log(res)
      })
    }
    function deletes() {
      axios({
        method: 'delete',
        url: "http://localhost:8080/userdelete",
        params: {
          id: 12,
          name: '瑶瑶'
        },
        headers: {
          a: 1,
          b: 2
        },
        data: {//delete方法只能只用对象方法传入data,不能用字符串的方法
          accont: '141546154',
          pwd: 123456
        }
        // data: `accont=141546154&pwd=123456`  不能使用
      }).then(res => {
        console.log(res)
      })
    }

2.2axios独立方法的使用

  • axios.get(url请求地址,请求体对象)

    url地址请求:string类型
    请求体对象:{params:{},headers:{}}

  • axios.post(url请求地址,请求体对象,配置对象)
  • axios.put(url请求地址,请求体对象,配置对象)
  • axios.patch(url请求地址,请求体对象,配置对象)

    url地址请求:string类型
    请求对象:{键名:键值…} 也可以是字符串的形式 “键名=键值&键名=键值” ,但是基本上都用对象的形式
    配置对象:{params:{},headers:{}}

  • axios.delete(url请求地址,配置对象)

    url地址请求:string类型
    配置对象:{params:{},headers:{},data:{键名:键值…}}

  // get 方法
    async function get() {
      let res = await axios.get('http://localhost:8080/user', {
        params: { id: 12, name: '瑶瑶' },
        headers: { a: 1, b: 2 },
      })
      console.log(res)
    }
    // post 方法
    async function post() {
      // let res = await axios.post('http://localhost:8080/login', `accont=141546154&pwd=123456`, {
      //   params: { id: 12, name: '瑶瑶' },
      //   headers: { a: 1, b: 2 },
      // })
      let res = await axios.post('http://localhost:8080/login', { accont: '141546154', pwd: 123456 }, {
        params: { id: 12, name: '瑶瑶' },
        headers: { a: 1, b: 2 },
      })
      console.log(res)
    }
    // put 方法
    async function put() {
      let res = await axios.put('http://localhost:8080/userput', `accont=141546154&pwd=123456`, {
        params: { id: 12, name: '瑶瑶' },
        headers: { a: 1, b: 2 },
      })
      console.log(res)
    }
    // patch 方法
    async function patch() {

      let res = await axios.patch('http://localhost:8080/userpatch', `accont=141546154&pwd=123456`, {
        params: { id: 12, name: '瑶瑶' },
        headers: { a: 1, b: 2 },
      })
      console.log(res)
    }
    // deletes 方法
    async function deletes() {
      let res = await axios.delete('http://localhost:8080/userdelete', {
        params: { id: 12, name: '瑶瑶' },
        headers: { a: 1, b: 2 },
        // data: `accont=141546154&pwd=123456`  
        data: { accont: '141546154', pwd: 123456 } //deletes 中的data只能是对象的形式传入 不能用字符串的形式
      })
      console.log(res)
    }

2.3axios的默认配置的使用

配置对象用来设定【请求的参数以及功能的设置】

/*
 * method:请求类型
 * url:请求的url
 * params:请求的url参数
 * headers:请求头
 * data:请求体设置
 * baseURL:设置url的公共部分
*/
//axios函数执行时,传入的对象就是[配置对象 ]
axios({
	配置对象
})
axios.get('/server',{配置对象});
axios.post('/server',{},{配置对象})
//axios的默认属性配置,一旦配置了基础url,则后续请求都无需再写,请求时会自动添加
axios.defaults.baseURL = "http://127.0.0.1";
axios.get('/server');
axios.get('/json-server');
axios.get('/settings');
//设置默认超时时间
axios.defaults.timeout = 3000;
//设置默认请求类型
axios.defaults.method = 'GET';

2.4 axios创建实例对象发送请求

//创建实例对象
let duanzi = axios.create({
	method:'GET',
	baseURL:"https://v0.yiketianqi.com",
	timeout:3000
});

//使用实例对象发送请求,使用方式与axios使用方式相同
duanzi({
    url:'/api?unescape=1&version=v61&appid=82294778&appsecret=4PKVFula&city=北京'
}).then(response=>{
    console.log(response);
});

2.5 axios拦截器使用

2.5.1 什么是拦截器

拦截器本质上其实就是一些函数,里面有两类拦截器,一个是请求拦截器;一个是响应拦截器。

请求拦截器的作用:对请求的内容以及参数做处理和检查。

响应拦截器的作用:对响应的内容进行预处理。

2.5.2 请求拦截器

axios.interceptors.request.use(config=>{
	console.log('请求拦截器成功');
	return config;
},error => {
	console.error('请求拦截器失败');
	return Promise.reject(error);
})

2.5.3 响应拦截器

axios.interceptors.response.use(response=>{
	console.log('响应拦截器成功');
	return config;
},error => {
	console.error('响应拦截器失败');
	return Promise.reject(error);
})
//发送请求
axios({
	method:'get',
	url:"http://127.0.0.1/server"
}).then(value=>{
	console.log(value);
},reason=>{
	console.error(reason);
})

拦截器可以设置多个,当请求拦截器有多个时则倒序执行;响应拦截器有多个时则正序执行;

axios.interceptors.request.use(config=>{
	console.log('请求拦截器成功-1');
	return config;
},error => {
	console.error('请求拦截器失败-1');
	return Promise.reject(error);
})

axios.interceptors.request.use(config=>{
	console.log('请求拦截器成功-2');
	return config;
},error => {
	console.error('请求拦截器失败-2');
	return Promise.reject(error);
})
axios.interceptors.response.use(response=>{
	console.log('响应拦截器成功-1');
	return config;
},error => {
	console.error('响应拦截器失败-1');
	return Promise.reject(error);
})

axios.interceptors.response.use(response=>{
	console.log('响应拦截器成功-2');
	return config;
},error => {
	console.error('响应拦截器失败-2');
	return Promise.reject(error);
})

2.6 axios取消请求

<body>
    <button>发送请求button>
    <button>取消请求button>
body>
<script>
    //获取按钮对象
	let btns = document.querySelectorAll('button');
	//声明变量
	let cancel = null;
	//发生点击事件
	btns[0].onclick = function(){
        //如果在发送之前想要取消则需要判断
        /*
         * 如果cancel已经为一个函数,则取消上一次请求
         * if(cancel){
             cancel();
         }
        */
        axios({
            method:"GET"
            url:"http://127.0.0.1/delay-server",
            cancelToken:new axios.CancelToken(function(c){
            	cancel = c;
        	});
        }).then(response=>{
            console.log(response);
        },error=>{
            console.warn(error);
        })
    }
    
    btns[1].onclick = function(){
        //调用cancel函数
        cancel();
    }
</script>

服务端

app.all('/delay-server',(request,response)=>{
	//延时 
    setTimeout(()=>{
        response.send('Hello abc');
    },3000);
})

CommonJS、ES6总结

一、常用的模块化代码:CommonJS、ES6

二、CommonJS语法

2.1 暴露

  • 暴漏任意数据
    module.exports = 值;
  • 暴露多个数据
    module.exports.键名 = 值;
  • 使用exports的方式暴露
    exports.键名 = 值

2.1 导入

let test = require("文件路径")
  • 文件:require('./文件名') require('../文件名')

省略文件后缀基本上是.js/.json为后缀的文件,除了这两个必须将后缀写清楚
文件中路径的./和…/是文件和文件之间在目录的层级上的路径,而非终端中的路径

  • 文件夹:require('./文件夹名') require('../文件夹名')

需要在这个文件夹里面查找package.json里面main属性的文件名,默认是index.js
如果在这个目录中这个文件则执行运行;
如果没有,有其他名称的文件,路径将自动补全:
require(‘./文件夹名/文件名’) require(‘…/文件夹名/文件名’)

  • 模块名:内置模块、第三方模块

如果是第三方模块名在当前文件夹下的node_modules目录里面没有找到,则自动上上一个文件目录的node_modules查找

注意事项:

  • 如果没有添加文件后缀,会默认按照.js/.json后缀的方式引入文件,同时有js和json同名的文件,没有添加文件后缀 js文件权重高
  • 其他文件后缀名,会按照.js方式载入
  • 如果是文件夹则会默认加载该文件夹下的package.json文件中main属性对应的文件
  • 如果是内置模块或者是npm安装的模块,直接使用包名字即可
  • npm引入包时,如果当前文件夹下的node_modules没有,则会自动向上查找

三、ES6模块化语法

  • 3.1 暴露

    • 分别暴露:export 变量声明
      export let 变量 = 值;
    • 统一暴露:
      export {变量1,变量2...}
    • 默认暴露:
      export default 值;
      值的数据类型是所有的常用数据类型(number、string、boolean、array、object、funciton)
  • 3.2 导入

    1. 适合于(分别暴露和统一暴露)的导入形式有两种:
    • 通用形式的导入:import * as 别名 from '子模块文件路径'
      这里的*表示所有,as表示别名 from来自于哪一个目标文件
    • 解构形式的导入:import {} from '子模块文件路径'
      {}里面写什么是子模块中export后面的变量名
    1. 适合于默认暴露的导入形式有两种:
    • 通用形式的导入:import * as 别名 from '子模块文件路径'
    • 默认形式的导入:import 变量名 from '子模块文件路径'

    注意:常见的错误写法 export default let a = 10;

三、browserify的使用

  • 全局安装 npm i -g browserify
  • 执行命令 browserify 入口文件 -o ./dist/bundle.js
    列:browserify ./build/app.js -o ./dist/bundle.js
    打包出能让浏览器识别的js
  • 然后运行

四、babel转化ES6代码并打包

注意:除了将ES6的语法转换之外,还会将ES6的模块化语法,转化为CommonJS模块化语法

  • 全局安装
npm i babel-cli -g browserify 
  • 局部安装

    注意:在项目的文件夹下安装

npm i babel-preset-es2015
  • 创建.babelrc文件

    这个文件是babel运行的配置文件

{
	"presets":[
		"es2015"  //将es6的代码转化成es5
	]
}
  • 使用 Babel 将 ES6 编译为 ES5 代码
babel ./src -d ./build

js/src打包入口文件路径
js/build 打包出口文件路径

  • 使用Browserify编译js上一步生成的js
browserify ./build/main.js -o ./dist/build.js

./build/main.js 入口文件路径
./dist/build.js 出口文件路径

  • test.html页面引入测试
  <script type="text/javascript" src="js/build/build.js"></script>

promise总结

一、JS中的错误处理 try…catch

语法固定 try…catch try 尝试的意思 catch 捕获
1. try catch捕获到错误之后, 后续代码可以继续执行
2. catch 可以将错误信息捕获到. error参数是一个错误对象, 有message(错误信息)和stack(错误跟踪,精准到行和列)两个属性,使用console.dir(error)打印输出查看
3. 抛出错误之后, 在 try 里面的报错的后续代码就不再执行
4. try 不能捕获语法错误(syntaxError). 其他三种类型错误可以捕获(typeError类型错误、RangeError范围错误、以及throw抛出错误).
5. 允许使用 throw 手动的抛出错误
6. throw可以抛出任意类型的数据

try {
   try中存入有可能会出现错误的代码(文件操作...、连接数据库....、操作数据库方法....、ajax请求...1、TypeError错误:
     let a = 10.4656;
     a = {}
     // 在try中如果有哪一句话发生了错误,则后面的语句将不再执行
     console.log(a.toFixed(2));
     //前面的语句发生了错误,则这句123是不会在控制台中输出
     // console.log(123);

     2、RangeError:范围错误
     //Array构造函数中的参数表示数组的预计长度,起始为0,不能为负数
     // let arr = new Array(-1);
     // console.log(arr);

     3、SyntaxError语法错误,catch是无法捕捉的!!!
     // if () {

     4throw抛出的错误,catch也是可以捕捉的,可以抛出任意类型错误

     // throw new Error('错误消息');
     // throw new TypeError('错误消息');
     //throw后面可以抛出任意的数据类型,只要抛出了catch中的错误对象都可以捕捉
     // throw 100;
     // throw "我是错误字符串";
     // throw true;
     // throw [1, 2, 3];

 } catch (e) {
     //catch方法需要传入一个参数,这个参数表示错误对象
     //错误对象也是对象,那么可以通过console.dir方法查看对象的结构
     //错误对象中包含了两个属性,一个是message(错误消息)另一个是stack(错误跟踪,精准到行和列)
     console.dir(e);
 }
 //try...catch后面的语句是可以正常运行的
        console.log('hello');

git、axios、模块化导出引入、promise、webpack、_第3张图片

二、promise基本使用

Promise的用途主要是为了实现一些异步任务,当这些异步任务的结果还没有得出的时候,此时Promise对象的状态仍然为pending

  • 创建promise对象(pending状态)
    const p = new Promise(executor)

    1、Promise本质是一个构造函数(产生一个实例化对象)
    2、Promise这个构造函数中需要传入一个参数,语法规定,必须要传入的,需要传入一个回调函数(executor 执行器函数)
    3、Promise构造函数中的实际参数的回调函数中还需要传递两个参数,且这两个参数仍然为回调函数
    这两个回调函数名基本不会改变:resolve(当前的状态是成功的)、reject(当前的状态是失败的)
    4、Promise主要为了实现异步编程(定时器、fs模块(文件写入、读取、删除…)、ajax、数据库操作方法)中提供成功/失败的结果
    5、Promise实例化对象有三个状态:pending(等待中...)、fulfilled(成功的状态)、rejected(失败的状态)
    6、Promise是通过其实例化对象的三个不同的状态来控制异步编程功能
    7、executor执行器函数中的两个形式参数也是可选参数,可加可不加,
    什么情况会添加?当如果想要改变Promise实例化对象的状态的时候是需要添加的,默认情况下Promise实例化对象的状态为pending

执行器回调函数中的两个回调函数作用:(resolve,reject)=>{}

  • reject的作用就是把Promise的状态从pending置为rejected,将实参设置到这个属性PromiseResult中,这样在then中就能捕捉到reject的回调函数
  • resolve的作用就是把Promise的状态从pending置为resolved,将实参设置到这个属性PromiseResult中,这样在then中就能捕捉到resolve的回调函数
const p = new Promise((resolve,reject)=>{
	//在回调函数中启动异步任务
    setTimeout(()=>{
        if(成功){
            resolve(实参);
        }else{
            reject(实参);
        }
    },2000)
})
  • 实例对象调用Promise原型中的then方法来完成对结果的处理
p.then((value)=>{
	//成功
},(reason)=>{
	//失败
})

三、Promise的状态改变

  • pending变为fulfilled
  • pending变为rejected

说明:只有这2种,且一个promise对象只能改变一次状态,状态一经改变,不可逆转

​ 无论变为成功还是失败,都会有一个结果数据

​ 成功的结果数据一般称为value,失败的结果数据一般称为reason

四、Promise实例对象的两个属性

  • PromiseState

    此属性为promise对象的状态属性。

    • fulfilled:成功的状态
    • rejected:失败的状态
    • pending:初始化的状态

    【注】状态只能由pending->fulfilled 或者是 pending->rejected

  • PromiseResult

    此属性为promise对象的结果值(resolve以及reject函数的形参值)
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q8uod8Ow-1686052789729)(null)]

五、node中的promisify

  • promisify (只能在 NodeJS 环境中使用)
  • promisify 是 util 模块中的一个方法 util 是 nodeJS 的内置模块
  • 作用: 返回一个新的函数, 函数的是 promise 风格的.
const util = require('util');
const fs = require('fs');
//promisify这个方法中需要传入一个以回调函数中是错误对象为优先的方法名
const mineReadFile = util.promisify(fs.readFile);

mineReadFile('./resource/2.html').then(value => {
    console.log(value.toString());
}, reason => {
    console.log(reason);
});

六、then 方法

then:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,Promise的实例化对象调用Promise原型属性身上的then方法也是有返回值的,返回一个新的Promise对象

  • 成功的状态:执行第一个回调函数
  • 失败的状态:执行第二个回调函数

then方法返回一个Promise对象,它的的返回状态值的判断:

1、如果返回的是非promise的任意值, 新promise变为fulfilled, PromiseResult返回的值 ,如果没有retuen 返回值 PromiseResultundefined
2、如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
(当下这个新的Promise对象的状态将决定于then方法返回的Promise对象的状态,结果值亦然)
3、如果抛出异常, 新promise变为rejected, reason为抛出的异常

const p = new Promise((resolve,reject)=>{
     resolve('ok');
});

let result = p.then(value=>{
	1throw '错误信息';// 1抛出异常 错误
	2return 100;  // 值可以是字符串、数字、boolean、null、undefined、数组、对象都变为PromiseResult的结果
	3return new Promise((resolve,reject) => {
         // resolve();
         // reject();
         // throw 404;
        result的结果 取决于  此时设置的不同的状态 ,不设置的话result为pending
      })
},reason=>{
	console.log(reason);
});

console.log(result);
1、抛出异常的结果: PromiseState为rejected   PromiseResult为抛出的错误信息
2、 非promise的任意值  结果 :PromiseState为fulfilled   PromiseResult为return返回的值
3、result的结果 取决于  此时设置的不同的状态 ,不设置的话result为pending

当then方法没有传递成功/失败的回调函数的时候,那么p2的这个对象的状态和结果值???
如果then在书写的时候没有明确体现出成功/失败的时候,程序将默认补全
如果p1的状态为fulfilled的时候,then方法将补全成功回调函数为:value=>value 状态为fulfilled p1的结果值就是p2的结果值

   let p1 = new Promise((resolve, reject) => {
        resolve('ok');
    })
  //  let p2 = p1.then();  会转变为以下形式
    let p2 = p1.then(value => value);
    console.log(p2);

如果p1的状态为rejected的时候,then方法将补全失败回调函数为:reason=>{throw reason} p1的状态和结果值和p2是一致的

    let p1 = new Promise((resolve, reject) => {
        reject('error');
    })
 //  let p2 = p1.then();  会转变为以下形式
    let p2 = p1.then(() => { }, reason => {
        throw reason;
    });
    console.log(p2);

七、Promise的链式调用

通过then方法来实现链式调用

const p = new Promise((resolve,reject)=>{
	//resolve('ok');
    reject('error');
});

p.then(value=>{
	console.log(value);
},reason=>{
	console.log(reason);//error 失败状态,进入失败的函数
}).then(value=>{
	console.log(value);//undefined  此时的值取决于上一个Promise对象的状态
},reason=>{
	console.log(reason);
})

将 then 方法 的Promise对象的返回状态值的判断弄通这个链式调用中的值就懂了

八、终止Promise链条

通过 return new Promise((resolve, reject) => {}); 返回一个pending状态的promise对象 这样后续的链式调用就不再执行

new Promise((resolve, reject) => {
    resolve(111);
}).then(value=>{
    console.log(value);
    console.log(222);
    //
    // return false;
    // throw '出错啦';
    //有且只有一种方式 返回一个pending状态的promise对象
    return new Promise((resolve, reject) => {});
}).then(value => {
    console.log(333);
}).then(value => {
    console.log(444);
}).catch(reason => {
    console.log(reason);
});

九、Promise对象下的API方法

9.1.catch方法

功能是可以单独用来指定失败的回调函数

	let p1 = new Promise((resolve, reject) => {
      reject('error')
    })
    p1.catch(reason => {
      console.log(reason); //error
    })

catch方法也可以和then方法连用
当如果then方法可以catch方法连用的时候,并且then里面也有失败的回调函数的时候,具体是否还会向下执行catch
取决于then方法返回的那个新的Promise实例化对象的状态是否是失败的,因为catch方法是专门用于指定失败状态的这么一个方法
如果是失败的,会执行catch,反之不会

	let p1 = new Promise((resolve, reject) => {
      reject('error')
    })
    p1.then(value => {
      console.log(value)
    }, reason => {//进入到失败的回调
      // console.log(reason)
      return new Promise((resolve, reject) => {
        reject('错误...')
      })
    }).catch(reason => {//通过返回值进入到catch
      console.log(reason); //错误...
    })

异常(错误)穿透
当如果有多个需要执行的成功时的回调函数,可以不需要每一次都写失败回调,可以统一最后利用catch
当如果promise对象的状态为reject的话,会一直向下穿透直到catch方法

let p1 = new Promise((resolve, reject) => {
    reject('error')
 })
p.then(value=>{
    console.log(value);
}).then(value=>{
    console.log(value);
}).catch(reason=>{
    console.log(reason);//error
})

catch的返回值的用法和then是一样的 catch方法返回一个Promise对象,它的的返回状态值和then()方法是一样的

	let p1 = new Promise((resolve, reject) => {
      reject('error')
    })
    let p2 = p1.catch(reason => {
      console.log(reason); //error
    })
    console.log(p2) //Promise对象

9.2 resolve方法

创建一个成功状态的Promise实例化对象

  • 情况1:当如果resolve方法传递的为非Promise实例化对象的时候,
    则p1这个对象的状态为fullfilled,结果值为resolve方法的实际参数值
   let p1 = Promise.resolve(100);
     console.log(p1);
  • 情况2:当resolve方法传递的是promise实例化对象的时候,
    p2的状态和结果值完全取决于resolve方法的参数中的promise对象的状态和结果值
   let p2 = Promise.resolve(new Promise((resolve, reject) => {
       resolve('success');
   }))
   console.log(p2) //fulfllted 状态  值为success

9.3reject方法

返回的结果始终为失败的Promise对象
Promise.reject(值) 无论值是什么类型 都将已错误的值返回

 let p1 = Promise.reject(100);
console.log(p1); //  Promise对象 失败状态  值为100

  //reject的结果值仍然是reject这个方法的实际参数值
  let p1 = Promise.reject(new Promise((resolve, reject) => {
    resolve('success');
  }));
  console.log(p1);//  Promise对象 失败状态  值为传递的参数这个新的promise  看下图输出

git、axios、模块化导出引入、promise、webpack、_第4张图片

9.4 all方法

作用:针对于多个Promise的异步任务进行处理

接收的参数:参数类型是一个数组,数组里面放的是promise的实例化对象

返回值:promise对象,状态由promise数组中的对象状态决定

  • 若每个对象状态都为成功,则返回的promise对象状态为成功,

​ 成功的结果值为每个promise对象成功结过值组成的数组

  • 不论有几个失败状态的对象 若任意一个对象状态为失败,则返回的promise对象状态为失败,

​ 失败的结果值为发现的第一个失败的promise对象的结果值 (以最快返回的第一个失败)

最终的请求时间是所有请求中耗时最长的请求所用的时间

let p1 = new Promise((resolve, reject) => {
            resolve('ok');
})
let p2 = Promise.resolve('success');
let p3 = Promise.resolve('okk');
let result = Promise.all([p1, p2, p3])
console.log(result);

git、axios、模块化导出引入、promise、webpack、_第5张图片

10.5 race方法

Promise.race() race 赛跑的意思

参数: promise 数组

返回结果: promise 对象

状态由『最先改变状态的 promise对象』决定

结果值由 『最先改变状态的 promise对象』决定

race方法是需要看哪一个Promise对象的状态已经不再是pending了,
不管是fulfilled还是rejected,只要修改了则修改的这个对象的状态和结果值直接就是arr的状态和结果值(最先出现结果的值就会输出)

let p1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('ok');
            }, 2000)
});
let p2 = Promise.resolve('success');
let p3 = Promise.resolve('oh hou');
let result = Promise.race([p1, p2, p3]);
console.log(result);// 成功状态的  success  p1 有定时器所有慢 p2 先输出

10.6 Promise.allSettled()

allSettled方法
参数仍然为promise 数组数组
返回的也是一个Promise实例化对象,其中包括两个状态,一个是fulfilled,一个是rejected

Promise.allSettled()方法,用来确定要一组异步操作是否都结束了(不管成功或失败)。
状态是fulfillesd ,值是以对象的形式返回每一项的状态和值 组成的数组

所以,它的名字叫"Settled",包含了"fufilled"和"rejected"两种情况.

最终的请求时间是所有请求中耗时最长的请求所用的时间
在这里插入图片描述

<script>
    function ajax(url) {
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();
        xhr.open('get', url, true);
        xhr.send();
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.responseText);
                } else {
                    reject(xhr.responseText);
                }
            }
        }
    })

}
//类比Promise下的all方法和allSettled
// Promise.all([ajax('http://www.xiongmaoyouxuan.com/api/tabs'),
// ajax('https://m.maizuo.com/gateway?cityId=110100&k=4770248')
// ]).then(value => {
//     console.log(value)
// }).catch(error => {
//     console.log(error);
// })

Promise.allSettled([ajax('http://www.xiongmaoyouxuan.com/api/tabs'),
                    ajax('https://m.maizuo.com/gateway?cityId=110100&k=4770248')
                   ]).then(value => {
    // console.log(value)
    let successList = value.filter(item => item.status === 'fulfilled');
    console.log(successList)

    let errorList = value.filter(item => item.status === 'rejected');
    console.log(errorList)
}).catch(error => {
    console.log(error);
})
</script>

10.7 Promise.any()

参数还是数组,数组中的内容是Promise实例化对象
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfiilled状态;

如果所有参数实例都变成rejected,包装实例就会变成rejected状态。

Promise.any()跟Promise.race()方法很像,但是有一点不同,
就是Promise.any()不会因为某个Promise变成rejected状态而结束,
必须等到所有参数Promise变成rejected状态才会结束。

10.8 Promise.finally()

finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象变成fufilled还是rejected状态,最终都会被执行。

finally方法中的回调函数是不接受参数的,因为无论前面是fulfilled状态还是rejected状态, 它都是执行。

const p = new Promise((resolve, reject) => {
    // resolve('ok');
    reject('error');
});
p.then(res => {
    console.log(res);
}).catch(err => {
    console.log(err);
}).finally(() => {
    console.log('finally')
})

十、async和await

async/await 是ES7提出的基于Promise的解决异步的最终方案。

10.1 async函数

async是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值。

因此对async函数可以直接then,返回值就是then方法传入的函数。

async函数的返回值是一个Promise对象,这个Promise对象的状态到底是成功还是失败,取决于return后面值的类型
如果值类型为基本数据类型/引用数据类型, 则返回的Promise对象的状态为成功
如果值类型为promise实例化对象的话,则状态和返回的这个对象的状态有关联,状态值也是一样的

// async基础语法
async function fun0(){
    console.log(1);
    return 1;
}
fun0().then(val=>{
    console.log(val) // 1,1
})

async function fun1(){
    console.log('Promise');
    return new Promise(function(resolve,reject){
        resolve('Promise')
    })
}
fun1().then(val => {
    console.log(val); // Promise Promise
}
//声明一个async函数
async function main() {
    console.log('async function');
    //情况1:返回非promise对象数据
    return 'hahaha';
    //情况2:返回是promise对象数据
    /* return new Promise((resolve, reject) => {
		// resolve('ok');
		reject('error');
	}) */
    //情况3:抛出异常
    // throw new Error('出错啦!!!');
}
let result = main().then(value => {
    console.log(value);
});
console.log(result);

10.2 await表达式

await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待

await 修饰的如果是Promise对象,可以获取Promise成功状态的结果值,且取到值后语句才会往下执行;
如果不是Promise对象:把这个非promise的东西当做await表达式的结果。
await后面是Promise成功状态的结果值
await后面如果是一个失败的Promise对象,则结果值需要通过使用try…catch来捕获得到
注意事项

  • await必须写在async函数中,但是async函数中可以没有await
  • 如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
async function fun(){
    let a = await 1;
    let b = await new Promise((resolve,reject)=>{
        setTimeout(function(){
            resolve('setTimeout')
        },3000)
    })
    let c = await function(){
        return 'function'
    }()
    console.log(a,b,c)
}
fun(); // 3秒后输出: 1 "setTimeout" "function"
function log(time){
    setTimeout(function(){
        console.log(time);
        return 1;
    },time)
}
async function fun(){
    let a = await log(1000);
    let b = await log(3000);
    let c = log(2000);
    console.log(a);
    console.log(1)
}
fun(); 
// 立即输出 undefined 1
// 1秒后输出 1000
// 2秒后输出 2000
// 3秒后输出 3000
async function main() {
    //1、如果await右侧为非promise类型数据
    var rs = await 10;
    var rs = await 1 + 1;
    var rs = await "非常6+7";

    //2、如果await右侧为promise成功类型数据
    var rs = await new Promise((resolve, reject) => {
        resolve('success');
    })

    //3、如果await右侧为promise失败类型数据,需要借助于try...catch捕获
    try {
        var rs = await new Promise((resolve, reject) => {
            reject('error');
        })
        } catch (e) {
            console.log(e);
        }
}
main();
// 使用async/await获取成功的结果

// 定义一个异步函数,3秒后才能获取到值(类似操作数据库)
function getSomeThing(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve('获取成功')
        },3000)
    })
}

async function test(){
    let a = await getSomeThing();
    console.log(a)
}
test(); // 3秒后输出:获取成功

十一、代码

ES5写法

(function (window) {
    // executor是执行器函数
    function Promise(executor) {
        //构造函数中的this一定是指向其实例化对象的
        // 定义实例属性state,初始值为pending
        this.PromiseState = 'pending';
        // 定义实例属性result,初始值为undefined
        this.PromiseResult = undefined;
        // 定义实例属性callbackFun,起始值为一个数组
        this.callbackFun = [];
        /* [
            {onResolved:function(){},onRejected:function(){}},
            {onResolved:function(){},onRejected:function(){}},
            {onResolved:function(){},onRejected:function(){}}
        ] */

        // 定义resolve函数
        const _resolve = value => {
            // 当状态已经被更改过,不允许再次更改
            if (this.PromiseState !== 'pending') return;
            //在修改状态之前需要考虑一件事,Promise实例化对象的状态是否仍然是pending 
            //如果不是pending了,不管是fulfilled还是rejected,就不会执行后面的代码
            // 将状态更改为成功(fulfilled)
            this.PromiseState = 'fulfilled';
            // 成功值为value
            this.PromiseResult = value;
            //运行执行器函数内部的异步代码
            // console.log(this.callbackFun)
            this.callbackFun.forEach(item => {
                item.onResolved();
            })
        }
        // 定义reject函数
        const _reject = reason => {
            // 当状态已经被更改过,不允许再次更改
            if (this.PromiseState !== 'pending') return;
            // 将状态更改为失败
            this.PromiseState = 'rejected';
            // 将result设置为reason
            this.PromiseResult = reason;
            this.callbackFun.forEach(item => {
                item.onRejected();
            })
        }
        try {
            executor(_resolve, _reject);
        } catch (err) {
            _reject(err);// 状态更改为失败,值为异常信息
        }



    }

    // Promise.prototype.then = function () { }


    //对象间的合并
    //第二个参数(源对象)向第一个参数(目标对象)合并
    //合并的时候,如果两个对象中有相同的属性,则后者会覆盖前者
    Object.assign(Promise.prototype, {
        // onResolved:成功回调
        // onRejected:失败回调

        then(onResolved, onRejected) {

            //判断当then方法里面没有传递两个实际参数的回调函数的时候,需要添加默认值
            //instanceof是判断一个值是否所属于某一个构造函数的实例化对象
            //补充成功回调函数
            if (!(onResolved instanceof Function)) {
                onResolved = value => value; // value=>{return value}
            }

            //补充失败回调函数
            if (!(onRejected instanceof Function)) {
                onRejected = reason => {
                    throw reason;
                };
            }

            return new Promise((resolve, reject) => {

                const _common = function (callback) {
                    setTimeout(() => {
                        try {
                            // value是成功回调的返回值
                            const value = callback(this.PromiseResult);
                            // 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
                            if (value instanceof Promise) {
                                value.then(v => {
                                    resolve(v);
                                }, r => {
                                    reject(r);
                                });
                            }
                            else {
                                // 不是Promise实例,将返回的Promise状态设置为成功,值为value
                                resolve(value);
                            }
                        } catch (err) {
                            // 有异常,将返回Promise的状态更改为失败,值为err
                            reject(err);
                        }

                    })
                }
                // 状态成功调用onResolved

                //这两种状态的改变相当于是同步代码的直接改变
                // p1的状态为成功
                if (this.PromiseState === 'fulfilled') {
                    _common.call(this, onResolved);
                } else if (this.PromiseState === 'rejected') {
                    _common.call(this, onRejected);
                } else {
                    //当异步任务没有执行完毕的时候,此时Promise实例化对象的状态为pending
                    //但是在pending的期间最终结果到底是fulfilled还是rejected,都有可能
                    //可以在当前Promise实例化对象身上添加一个回调函数的属性,用来存储两个回调(成功的回调,失败的回调)
                    this.callbackFun.push({
                        onResolved: _common.bind(this, onResolved),
                        onRejected: _common.bind(this, onRejected)
                    })
                }
            })
        },
        catch(onRejected) {
            //既然catch方法和then方法做的功能是一致的,那么我们没必要将代码在复制粘贴一份,而选择直接调用then方法
            // console.log(onRejected);
            return this.then(undefined, onRejected);
        }
    })

    //Promise对象下的方法添加
    // console.dir(Promise);

    Promise.resolve = function (value) {
        return new Promise((resolve, reject) => {
            //判断value的类型到底是不是一个Promise对象
            if (value instanceof Promise) {
                // console.log('实例化对象', value);
                // value.then(v => {
                //     resolve(v);
                // }, r => {
                //     reject(r);
                // })

                //简写的形式
                value.then(resolve, reject);
            } else {
                resolve(value);
            }
        })
    }

    Promise.reject = function (value) {
        return new Promise((resolve, reject) => {
            //直接将Promise实例化对象状态更改成rejected
            reject(value);
        })
    }

    Promise.all = function (value) {
        // 定义一个变量,用来计数(计成功的Promise的数量,到时候和数组的数量做对比)
        let index = 0;
        //定义一个数组,数组用来装如果all方法里面都是成功的Promise对象的结果值
        //new Array(数字):表示预设数组长度
        let arr = new Array(value.length); // [??]

        return new Promise((resolve, reject) => {
            value.forEach((item, i) => {
                // console.log('数组的每一项:', item);
                // console.log('数组的下标:', i)
                item.then(v => {
                    //只要有一个成功的Promise实例化对象,就让计数器+1
                    index++;
                    arr[i] = v;
                    if (index === value.length) {
                        //只要计数器数值和all方法中的长度一致,则证明数组中每一个元素都是成功的Promise对象
                        resolve(arr);
                    }
                }, r => {
                    //只要有失败,状态将立即更改
                    reject(r);
                })
            })
        })

    }

    Promise.race = function (value) {
        return new Promise((resolve, reject) => {
            value.forEach(item => {
                //从数组中的第一个Promise对象开始循环,只要能够进入到then的回调函数之中,不管是哪一个回调函数
                //说明此时Promise对象的状态一定不为pending,所以不管是成功还是失败,直接修改状态
                item.then(v => {
                    resolve(v);
                }, reason => {
                    reject(reason)
                })
            })
        })
    }

    window.Promise = Promise;
})(window);

class写法

(function (window) {
    //声明类
    class Promise {

        constructor(executor) {
            //this指向的是Promise这个类的实例化对象
            this.PromiseState = 'pending';
            this.PromiseResult = undefined;
            //当执行器函数内部的代码为异步代码的时候
            this.callbackFun = [];

            // 定义resolve函数
            const _resolve = value => {
                // 当状态已经被更改过,不允许再次更改
                if (this.PromiseState !== 'pending') return;
                //在修改状态之前需要考虑一件事,Promise实例化对象的状态是否仍然是pending 
                //如果不是pending了,不管是fulfilled还是rejected,就不会执行后面的代码
                // 将状态更改为成功(fulfilled)
                this.PromiseState = 'fulfilled';
                // 成功值为value
                this.PromiseResult = value;
                this.callbackFun.forEach(item => {
                    item.onResolved();
                })
            }

            // 定义reject函数
            const _reject = reason => {
                // 当状态已经被更改过,不允许再次更改
                if (this.PromiseState !== 'pending') return;
                // 将状态更改为失败
                this.PromiseState = 'rejected';
                // 将result设置为reason
                this.PromiseResult = reason;
                this.callbackFun.forEach(item => {
                    item.onRejected();
                })
            }

            try {
                executor(_resolve, _reject);
            } catch (err) {
                _reject(err);// 状态更改为失败,值为异常信息
            }
        }

        then(onResolved, onRejected) {

            //判断当then方法里面没有传递两个实际参数的回调函数的时候,需要添加默认值
            //instanceof是判断一个值是否所属于某一个构造函数的实例化对象
            //补充成功回调函数
            if (!(onResolved instanceof Function)) {
                onResolved = value => value; // value=>{return value}
            }

            //补充失败回调函数
            if (!(onRejected instanceof Function)) {
                onRejected = reason => {
                    throw reason;
                };
            }

            return new Promise((resolve, reject) => {

                const _common = function (callback) {
                    setTimeout(() => {
                        try {
                            // value是成功回调的返回值
                            const value = callback(this.PromiseResult);
                            // 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
                            if (value instanceof Promise) {
                                value.then(v => {
                                    resolve(v);
                                }, r => {
                                    reject(r);
                                });
                            }
                            else {
                                // 不是Promise实例,将返回的Promise状态设置为成功,值为value
                                resolve(value);
                            }
                        } catch (err) {
                            // 有异常,将返回Promise的状态更改为失败,值为err
                            reject(err);
                        }

                    })
                }
                // 状态成功调用onResolved

                //这两种状态的改变相当于是同步代码的直接改变
                // p1的状态为成功
                if (this.PromiseState === 'fulfilled') {
                    _common.call(this, onResolved);
                } else if (this.PromiseState === 'rejected') {
                    _common.call(this, onRejected);
                } else {
                    //当异步任务没有执行完毕的时候,此时Promise实例化对象的状态为pending
                    //但是在pending的期间最终结果到底是fulfilled还是rejected,都有可能
                    //可以在当前Promise实例化对象身上添加一个回调函数的属性,用来存储两个回调(成功的回调,失败的回调)
                    this.callbackFun.push({
                        onResolved: _common.bind(this, onResolved),
                        onRejected: _common.bind(this, onRejected)
                    })
                }
            })
        }

        catch(onRejected) {
            //既然catch方法和then方法做的功能是一致的,那么我们没必要将代码在复制粘贴一份,而选择直接调用then方法
            // console.log(onRejected);
            return this.then(undefined, onRejected);
        }

        static resolve = function (value) {
            return new Promise((resolve, reject) => {
                //判断value的类型到底是不是一个Promise对象
                if (value instanceof Promise) {
                    // console.log('实例化对象', value);
                    // value.then(v => {
                    //     resolve(v);
                    // }, r => {
                    //     reject(r);
                    // })

                    //简写的形式
                    value.then(resolve, reject);
                } else {
                    resolve(value);
                }
            })
        }

        static reject = function (value) {
            return new Promise((resolve, reject) => {
                //直接将Promise实例化对象状态更改成rejected
                reject(value);
            })
        }

        static all = function (value) {
            // 定义一个变量,用来计数(计成功的Promise的数量,到时候和数组的数量做对比)
            let index = 0;
            //定义一个数组,数组用来装如果all方法里面都是成功的Promise对象的结果值
            //new Array(数字):表示预设数组长度
            let arr = new Array(value.length); // [??]

            return new Promise((resolve, reject) => {
                value.forEach((item, i) => {
                    // console.log('数组的每一项:', item);
                    // console.log('数组的下标:', i)
                    item.then(v => {
                        //只要有一个成功的Promise实例化对象,就让计数器+1
                        index++;
                        arr[i] = v;
                        if (index === value.length) {
                            //只要计数器数值和all方法中的长度一致,则证明数组中每一个元素都是成功的Promise对象
                            resolve(arr);
                        }
                    }, r => {
                        //只要有失败,状态将立即更改
                        reject(r);
                    })
                })
            })

        }

        static race = function (value) {
            return new Promise((resolve, reject) => {
                value.forEach(item => {
                    //从数组中的第一个Promise对象开始循环,只要能够进入到then的回调函数之中,不管是哪一个回调函数
                    //说明此时Promise对象的状态一定不为pending,所以不管是成功还是失败,直接修改状态
                    item.then(v => {
                        resolve(v);
                    }, reason => {
                        reject(reason)
                    })
                })
            })
        }
    }
    window.Promise = Promise;
})(window)

webpack代码

webpak.prod.js

//导入模块
const path = require('path');

//导入安装的第三方的包

//单独抽离成独立的css文件
const miniCssExtractPlugin = require('mini-css-extract-plugin');

//css压缩的
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

//html文件的打包
const htmlWebpackPlugin = require('html-webpack-plugin');

//eslint代码检查包
const eslintWebpackPlugin = require('eslint-webpack-plugin');


// console.log(path.resolve('E:\\BJ0313\\day20\\代码\\webpack\\demo1', './abc'));

//__dirname:表示当前文件在定义时期所在的绝对路径:E:\\BJ0313\\day20\\代码\\webpack\\demo1\\config
// console.log(path.resolve(__dirname, '../dist'));

//向外暴露一个对象
module.exports = {
    //webpack打包的时候有五大核心:
    /* 
     *  entry(打包入口文件地址)
     *  output(打包文件路径出口)
     *  mode(打包的模式)
     *  ----------------------
     *  前面的三个属性可以单独为以.js结尾的文件进行打包
     * 
     *  但是,如果文件结尾为.css/.less/.png/.jpg/.gif/.mp4/.woff....等等这些后缀
     *  则需要模块以及插件来支持
     *  module(加载器)  
     *  plugins(插件)
     */

    //这个对象中的五个属性书写没有任何的顺序,但是一般情况下先从入口、出口、模块、插件、模式等这种顺序

    //打包的入口文件地址是针对于运行终端来说,而非这个webpack.prod.js和src目录之间的关系!!!!
    entry: './src/js/app.js',
    //打包的出口
    output: {
        //打包后的文件夹路径
        //path属性是语法,不能修改,后面的值是一个绝对路径
        //E:\BJ0313\day20\代码\webpack\demo1\dist
        //自动产生一个路径,需要借助于node中的内置模块:path
        path: path.resolve(__dirname, '../dist'),
        filename: 'js/bundle.js',
        //每一次重新打包的时候都会将上一次的结果清除掉
        clean: true,
         //公共路径
        publicPath: '/'
    },
    //打包模式
    mode: 'production',

    //加载器(loader)
    module: {
        //rules规则,这个rules后面是一个数组,里面存入的是对象形式的值,也就是说,有一个规则就配置一个对象
        rules: [
            //.css后缀的规则,那么就定义一个对象
            {
                //test是正则中的检测,后面的值写的是正则的规则
                //其中[.]和\.的含义等同,目的都是为了将.这个字符转化成普通的字符.
                //因为.在正则表达式中表示除了换行符以外的任意单个字符,保证用户在创建文件名的时候一定是xxx.css
                test: /[.]css$/i,
                //use后面到底是数组还是字符串,取决于使用的时候是一个加载器还是多个加载器
                //如果是多个加载器的话,那么需要写成数组
                //反之如果是一个加载器,则可以直接定义成字符串
                //并且如果是数组的话,则数组的执行顺序是由右->左
                //css-loader的作用主要是加载.css结尾的文件,并解析执行里面你的css语法,返回css语句
                //style-loader的作用主要是在index.html的head标签里面添加一个style标签存入css语法
                //也就是说,src/css文件夹里面有一个css文件,就把这个文件里面的语句在style标签中写一遍
                //考虑到文件的数量和文件中内容的数量,这种形式不是很合适
                // use: ['style-loader', 'css-loader']

                //如果css代码偏多,文件偏多,最终会使得index.html文件内容偏多
                //所以需要一个单独的插件包将所有开发时使用的css文件的内容抽离出来成一个单独的新的css文件
                //这样的话就需要一个插件包:miniCssExtractPlugin
                use: [miniCssExtractPlugin.loader, 'css-loader', {
                    loader: 'postcss-loader',
                    options: {
                        postcssOptions: {
                            plugins: [
                                [
                                    'postcss-preset-env'
                                ],
                            ],
                        },
                    },
                }]
            },
            {
                test: /\.less$/i,
                //顺序:由右->左
                use: ['style-loader', 'css-loader', 'less-loader']
            },
            {
                test: /\.(gif|png|jpe?g|webp)$/i,
                //如果某一个文件的后缀需要使用加载器,则是use配置属性, 如果是图片则直接是type类型
                type: 'asset',
                //默认是小于8KB会自动转化成base64,大于8KB的图片会参与打包,保存在dist目录中
                //如果想要修改这种默认的图片大小,需要单独设置parser这个属性
                parser:
                {
                    dataUrlCondition: {
                        maxSize: 10 * 1024 // 小于10kb的图片会被base64处理,则不会打包进dist文件夹,这样就可以减少针对于图片的请求,也降低了图片保存在目录中的占位
                    }
                },
                generator: {
                    // 将图片文件输出到 static/imgs 目录中
                    // 将图片文件命名 [hash:8][ext][query]
                    // [hash:8]: hash值取8位,可自定义,写几文件名就是几位的
                    // [ext]: 使用之前的文件扩展名
                    // [query]: 添加之前的query参数
                    //这个文件的路径是根据之前output中path里面的../dist目录判断的,相当于在dist目录下做配置
                    filename: "static/imgs/[hash:8][ext][query]",
                }
            },
            {
                test: /\.(ttf|woff2?|mp4|avi|wmv)$/,
                type: "asset/resource",  //相当于执行了file-loader 将字体文件输出到dist打包目录中
                generator: {
                    filename: "static/media/[hash:10][ext]",
                }
            },
            {
                test: /\.js$/,
                exclude: /node_modules/, // 排除node_modules代码不编译
                loader: "babel-loader",
            },
             {
                //检测以.ejs结尾的文件
                test: /\.ejs$/,
                //使用ejs-loader加载器来检测
                loader: 'ejs-loader',
                //配置项
                options: {
                    //ejs模板页面中的变量名
                    //可以自定义
                    variable: 'data'
                }
            },
        ]
    },
    //插件
    plugins: [
        new miniCssExtractPlugin({
            //抽离的独立css文件名
            //filename中的路径和文件名都可以自定义
            filename: 'static/css/main.css'
        }),
        new CssMinimizerPlugin(),
        new htmlWebpackPlugin({
            //需要打包的文件路径是什么???
            template: path.resolve(__dirname, '../public/index.html'),
            //打包后的文件叫什么???
            filename: 'index.html',
            //是否将打包的bundle.js文件自动添加到打包的html文件里面,如果是,放在哪里???
            inject: 'body'
        }),
        new eslintWebpackPlugin({
            context: path.resolve(__dirname, '../src'),
        })
    ],
    //源代码和构建后的代码需要产生一个映射关系
    devtool: 'source-map'
}

webpak.dev.js

//导入
const ProdConfig = require('./webpack.prod');
//暴露
module.exports = {
    ...ProdConfig,
    //打包模式
    mode: 'development',
    //配置开发服务器
    devServer: {
        //主机地址:
        host: 'localhost',
        //端口号
        port: 3000,
        //是否自动打开浏览器
        open: true
    },
    //源代码和构建后的代码需要产生一个映射关系
    devtool: 'cheap-module-source-map'
}

你可能感兴趣的:(npm,和,node,webpack,git)