GIT总结
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
暂存区中的文件列表
clear
或ctrl + 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
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、请求urlurl: "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)
- 分别暴露:export 变量声明
-
3.2 导入
- 适合于(分别暴露和统一暴露)的导入形式有两种:
- 通用形式的导入:
import * as 别名 from '子模块文件路径'
这里的*表示所有,as表示别名 from来自于哪一个目标文件 - 解构形式的导入:
import {} from '子模块文件路径'
{}里面写什么是子模块中export后面的变量名
- 适合于默认暴露的导入形式有两种:
- 通用形式的导入:
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 - 然后运行
<script src="./dist/bundle.js"></script>
四、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 () {4、throw抛出的错误,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');
二、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 返回值 PromiseResult为undefined
2、如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
(当下这个新的Promise对象的状态将决定于then方法返回的Promise对象的状态,结果值亦然)
3、如果抛出异常,新promise变为rejected, reason为抛出的异常
const p = new Promise((resolve,reject)=>{resolve('ok');
});let result = p.then(value=>{1、throw '错误信息';// 1抛出异常 错误2、return 100; // 值可以是字符串、数字、boolean、null、undefined、数组、对象都变为PromiseResult的结果3、return 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 => {//通过返回值进入到catchconsole.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 看下图输出
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);
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,初始值为pendingthis.PromiseState = 'pending';// 定义实例属性result,初始值为undefinedthis.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';// 成功值为valuethis.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设置为reasonthis.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状态设置为成功,值为valueresolve(value);}} catch (err) {// 有异常,将返回Promise的状态更改为失败,值为errreject(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实例化对象状态更改成rejectedreject(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实例化对象,就让计数器+1index++;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';// 成功值为valuethis.PromiseResult = value;this.callbackFun.forEach(item => {item.onResolved();})}// 定义reject函数const _reject = reason => {// 当状态已经被更改过,不允许再次更改if (this.PromiseState !== 'pending') return;// 将状态更改为失败this.PromiseState = 'rejected';// 将result设置为reasonthis.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状态设置为成功,值为valueresolve(value);}} catch (err) {// 有异常,将返回Promise的状态更改为失败,值为errreject(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实例化对象状态更改成rejectedreject(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实例化对象,就让计数器+1index++;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中的内置模块:pathpath: path.resolve(__dirname, '../dist'),filename: 'js/bundle.js',//每一次重新打包的时候都会将上一次的结果清除掉clean: true,//公共路径publicPath: '/'},//打包模式mode: 'production',//加载器(loader)module: {//rules规则,这个rules后面是一个数组,里面存入的是对象形式的值,也就是说,有一个规则就配置一个对象rules: [//.css后缀的规则,那么就定义一个对象{//test是正则中的检测,后面的值写的是正则的规则//其中[.]和\.的含义等同,目的都是为了将.这个字符转化成普通的字符.//因为.在正则表达式中表示除了换行符以外的任意单个字符,保证用户在创建文件名的时候一定是xxx.csstest: /[.]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文件//这样的话就需要一个插件包:miniCssExtractPluginuse: [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'
}