20230404----重返学习-async与await-无限树形菜单-npm-终端窗口cmd控制台
day-042-forty-two-20230404-async与await-无限树形菜单-npm-终端窗口cmd控制台
async与await
async与await是Promise结合Generator函数的语法糖。
特性
-
async和await可以分开,一般不会分开。
-
async必须和函数一块使用,会返回一个Promise实例对象。
async function getData() {return 10; } console.log(getData()); getData().then((value) => {console.log(value);}).catch((err) => {console.log("err", err);});
-
返回值为ES5普通类型—>状态fulfilled,值为返回值。
async function getData() {return 10; } console.log(getData());
-
返回值默认是状态fulfilled,值为undefined。
async function getData() { } console.log(getData());
-
-
返回值为Promise实例对象
-
如果函数语句出错,会返回一个Promise实例对象。状态为rejected,值为错误原因对象。
-
但是控制台依旧会报错,要使用try和catch来捕获
async function getData() {console.log(a); } console.log(getData());
async function getData() {try {console.log(a);} catch (err) {console.log(err);}return 10; } console.log(getData());
async function getData() {console.log(a);return 10; } getData().then((value) => {console.log(value);}).catch((err) => {console.log("err", err);});
-
-
-
async的提出就是为了结合await使用
-
await后面可以跟普通值,默认会转化为一个Promise实例对象,状态为fulfilled,值为普通值。
async function getData() {console.log("111");const theNumber = 5;let res1 = await theNumber; //此时theNumber会转化成一个状态为fulfilled,值为5的Promise实例对象,之后变成微任务交由await解析,await解析为结果5,赋值给res1。console.log(res1); } getData();
- 但是一般使用await都要跟Promise实例对象(异步任务)
-
Promise实例对象里面一般是异步任务。
let thePromise = new Promise((resolve, reject) => {setTimeout(() => {resolve(100);}, 1000);console.log("111"); }); async function getData() {console.log("222");let res1 = await thePromise; //此时等待Promise实例对象thePromise转化成一个状态为fulfilled,值为100。之后交由await解析,await解析为结果100,赋值给res1。console.log(res1); } getData(); console.log("333");
-
- 但是一般使用await都要跟Promise实例对象(异步任务)
-
await同一句代码后面及上方都被认为是同步任务,以普通同步代码的方式在执行。但await同一行代码前面及下方都是异步任务。
let thePromise = new Promise((resolve, reject) => {setTimeout(() => {resolve(100);}, 1000);console.log("111"); }); async function getData() {console.log("222");let res1 = await thePromise;console.log(res1); } getData(); console.log("333");//"111" //"222"//await同一句代码后面及上方都被认为是同步任务 //"333" //100 //await同一行代码前面及下方都是异步任务。
-
await 必须等待同一句代码后面的任务成功完成,才能执行下方的代码
-
await 如果同一句代码后面的任务是失败的,下方的代码将不执行
let p = new Promise((resolve, reject) => {console.log(a); }); p.then((value) => {console.log(value); }).catch((err) => {console.log("err", err); });
async function getData() {console.log(a);return 10; } getData().then((value) => {console.log(value); }).catch((err) => {console.log("err", err); });
-
所以await一般配合try-catch来使用
async function getData() {try {console.log(a);} catch (err) {console.log(err);}return 10; }
- 也有人直接在async函数里整个包上try-catch,类似于.the()链传透。
- 个人感觉要排查问题时,最好是有可能报错的await外包一层,以方便同事排查。
const get = function get(url, callback) {let xhr = new XMLHttpRequest();xhr.open("GET", url, true);xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {let data = JSON.parse(xhr.response);callback(data);}};xhr.send(); }; function fn1() {return new Promise((resolve, reject) => {get("./data.json", function (data) {resolve(data);});}); } function fn2() {return new Promise((resolve, reject) => {get("./data.json", function (data) {reject(data);});}); } function fn3() {return new Promise((resolve, reject) => {get("./data.json", function (data) {resolve(data);});}); } //同步写法解决异步请求 async function getData() {try {let res1 = await fn1();let res2 = await fn2();let res3 = await fn3();console.log(res1, res2, res3);} catch (err) {console.log("有失败的结果,执行中断了", err);}// console.log("111") } getData(); async function getData1() {try {let res1 = await fn1();} catch (err) {console.log("有失败的结果,执行中断1", err);}try {let res2 = await fn2();} catch (err) {console.log("有失败的结果,执行中断2", err);}try {let res3 = await fn3();console.log(res1, res2, res3);} catch (err) {console.log("有失败的结果,执行中断3", err);}// console.log("111") } getData1()//等价于 fn1().then(value=>{console.log(value);return fn2() }).then(value=>{console.log(value);return fn3() }).then(value=>{console.log(value); }).catch(err=>{console.log(err); })
- 也有人直接在async函数里整个包上try-catch,类似于.the()链传透。
-
-
await的结果值是它后方状态为fulfilled的Promise实例对象的结果值。
-
async可以没有await,await必须先有async。
- await前面执行的代码都是同步代码,而await后面的代码,都是异步执行的。
- 单纯的async函数执行时,执行的步骤都是同步的,但返回的值必定是Promise实例对象。可以是返回出去的,也可以是返回普通值被浏览器包装成了Promise实例对象。
- async+await 就是异步任务,其中async函数在await前执行的代码都是同步的,但await之后执行的,就都是异步的了。
- 可以单纯地写一个async函数,里面都不使用await。但await关键字要放在async函数内。
- await前面执行的代码都是同步代码,而await后面的代码,都是异步执行的。
-
-
-
同步写法解决异步任务
const get = function get(url, callback) {let xhr = new XMLHttpRequest();xhr.open("GET", url, true);xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {let data = JSON.parse(xhr.response);callback(data);}};xhr.send(); }; function fn1() {return new Promise((resolve, reject) => {get("./data.json", function (data) {resolve(data);});}); } function fn2() {return new Promise((resolve, reject) => {get("./data.json", function (data) {reject(data);});}); } function fn3() {return new Promise((resolve, reject) => {get("./data.json", function (data) {resolve(data);});}); } //同步写法解决异步请求 // async function getData() { // try { // let res1 = await fn1(); // let res2 = await fn2(); // let res3 = await fn3(); // console.log(res1, res2, res3); // } catch (err) { // console.log("有失败的结果,执行中断了", err); // } // // console.log("111") // } // getData() async function getData() {let res1 = await fn1();let res2 = await fn2();let res3 = await fn3();console.log(res1, res2, res3);// console.log("111") } getData()
无限树形菜单
./data.json
[{"name": "前端开发基础","open": true,"children": [{"name": "HTML5核心知识","children": [{"name": "新增语义化标签"},{"name": "表单元素新特性"},{"name": "音视屏处理"},{"name": "canvas和webGL"},{"name": "新增JS中的API"}]},{"name": "CSS3核心知识","children": [{"name": "新增选择器"},{"name": "字体图标"},{"name": "常用的样式属性"},{"name": "背景的处理"},{"name": "transform变形"},{"name": "CSS3动画","children": [{"name": "transition过度动画"},{"name": "animation帧动画"},{"name": "3D动画的处理"}]},{"name": "新盒子模型属性","children": [{"name": "flex弹性盒子模型"},{"name": "box-sizing新盒子模型属性"},{"name": "cloumns多列布局"}]}]},{"name": "实战案例和布局技巧","children": [{"name": "实战案例练习","children": [{"name": "居中处理"},{"name": "同行排列"},{"name": "圣杯布局"},{"name": "双飞翼布局"},{"name": "滑动门"},{"name": "面包屑导航"}]},{"name": "响应式布局开发","children": [{"name": "viewport和dpi适配"},{"name": "@media媒体查询"},{"name": "rem等比缩放"},{"name": "百分比布局"}]}]}]},{"name": "前端开发核心","children": [{"name": "JS(ES6)核心","children": [{"name": "基础知识"},{"name": "闭包作用域及堆栈内存"},{"name": "面向对象和THIS处理"},{"name": "同步异步(事件循环、微任务、宏任务)"},{"name": "DOM事件和事件委托"},{"name": "设计模式"}]},{"name": "AJAX前后端交互","children": [{"name": "AJAX基础知识"},{"name": "跨域策略请求"},{"name": "TCP协议相关基础知识"},{"name": "性能和安全的初步优化"},{"name": "常用的AJAX库和插件"}]},{"name": "底层原理和高阶JS函数","children": [{"name": "函数柯里化"},{"name": "compos函数"},{"name": "惰性思想"},{"name": "组件插件封装"},{"name": "底层源码解读"}]}]},{"name": "前端工程化","children": [{"name": "VUE全家桶","children": [{"name": "基础知识"},{"name": "MVVM实现原理"},{"name": "路由处理"},{"name": "vuex公共状态管理"},{"name": "element-ui组件应用和二次封装"}]},{"name": "REACT全家桶","children": [{"name": "基础知识"},{"name": "MVC实现原理"},{"name": "DOM DIFF"},{"name": "Virtual DOM"},{"name": "路由处理"},{"name": "公共状态管理","children": [{"name": "REACT-REDUX、DAVS/SAGA等"},{"name": "compos函数"},{"name": "惰性思想"},{"name": "组件插件封装"},{"name": "底层源码解读"}]},{"name": "高阶租价"},{"name": "antd组件应用和二次封装"}]},{"name": "底层原理和高阶JS函数","children": [{"name": "函数柯里化"},{"name": "compos函数"},{"name": "惰性思想"},{"name": "组件插件封装"},{"name": "底层源码解读"}]},{"name": "工程化开发部署","children": [{"name": "webpack"},{"name": "git"},{"name": "linux"}]}]},{"name": "前端开发热门点","children": [{"name": "TypeScript"},{"name": "flutter"},{"name": "react native"},{"name": "小程序"},{"name": "性能和安全的优化"}]}
]
- 初代代码
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>zTree树形结构菜单</title><style>.container {box-sizing: border-box;margin: 20px auto;padding: 10px;width: 600px;border: 1px dashed #aaa;-webkit-user-select: none;user-select: none;}.level {display: none;font-size: 14px;margin-left: 10px;/* transition: height .3s linear 0s;overflow: hidden; */}.level.level0 {display: block;margin-left: 0;}.level li {position: relative;padding-left: 15px;line-height: 30px;}.level li .icon {position: absolute;left: 0;top: 9px;box-sizing: border-box;width: 12px;height: 12px;line-height: 8px;text-align: center;border: 1px solid #aaa;background: #eee;cursor: pointer;}.level li .icon:after {display: block;content: "+";font-size: 12px;font-style: normal;}.level li .icon.open:after {content: "-";}.level li .title {color: #000;}</style></head><body><div class="container"><ul class="level level0" id="zTree"><li><a href="javascript:;" class="title">第一级第一项</a><em class="icon open"></em><ul class="level" style="display: block"><li><a href="javascript:;" class="title">第二级第一项</a></li></ul></li><li><a href="javascript:;" class="title">第一级第二项</a></li><li><a href="javascript:;" class="title">第一级第三项</a></li></ul></div><!-- IMPORT JS --><!-- <script src="js/index.js"></script> --></body>
</html>
<script>
(function () {let zTree = document.getElementById("zTree");//事件委托--功能zTree.onclick = function (e) {let tar = e.target;//点击元素的相邻兄弟下一个ullet ulbox = tar.nextElementSibling;if (tar.tagName === "EM") {//点击展开和收缩按钮//contains判断是否具有某个class//有 open --->删除open ul隐藏if (tar.classList.contains("open")) {tar.classList.remove("open");ulbox.style.display = "none";} else {//没有 open --->添加open ul显示tar.classList.add("open");ulbox.style.display = "block";}}};//"异步方式"获取数据function getData() {return new Promise((resolve, reject) => {let xhr = new XMLHttpRequest();xhr.open("get", "./data.json");xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {let data = JSON.parse(xhr.response);resolve(data);}};xhr.send();});}//获取数据async function fn() {let data = await getData();let str = render(data);zTree.innerHTML = str;}fn();//循环渲染function render(data) {let str = "";data.forEach((item) => {let { name, children, open } = item;str += `<li><a href="javascript:;" class="title">${name}</a>${children? `<em class="icon ${open ? "open" : ""}"></em> <ul class="level" style="display: ${open ? "block" : "none"};"> ${render(children)} </ul>`: ""}</li>`;});return str;}//方法一:// getData()// .then((value) => {// console.log(value);// })// .catch((err) => {// console.log(err);// });//方法二:// async function render() {// try {// let data = await getData();// console.log(data);// } catch (error) {}// }// render();
})();
</script>
- 改进
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>zTree树形结构菜单</title><!-- IMPORT CSS --><style>.container {box-sizing: border-box;margin: 20px auto;padding: 10px;width: 600px;border: 1px dashed #aaa;-webkit-user-select: none;user-select: none;}.container .level {display: none;font-size: 14px;margin-left: 10px;/* transition: height .3s linear 0s;overflow: hidden; */}.container .level.level0 {display: block;margin-left: 0;}.container .level li,.container .level .the-item {position: relative;padding-left: 15px;line-height: 30px;}.container .level li .icon,.container .level .the-item .icon {position: absolute;left: 0;top: 9px;box-sizing: border-box;width: 12px;height: 12px;line-height: 8px;text-align: center;border: 1px solid #aaa;background: #eee;cursor: pointer;}.container .level li .icon:after,.container .level .the-item .icon:after {content: "+";display: block;font-size: 12px;font-style: normal;}.container .level li .icon.open:after,.container .level .the-item .icon.open:after {content: "-";}.container .level li .title,.container .level .the-item .title {color: #000;}</style></head><body><div class="container"><ul class="level level0" id="zTree"><li class="the-item"><a class="title" href="javascript:;">第一级第一项</a><em class="icon open"></em><ul class="level" style="display: block"><li class="the-item"><a href="javascript:;" class="title">第二级第一项</a></li></ul></li><li class="the-item"><a href="javascript:;" class="title">第一级第二项</a></li><li class="the-item"><a href="javascript:;" class="title">第一级第三项</a></li></ul></div><!-- IMPORT JS --></body>
</html>
<script>const theObject = (function () {let zTree = document.querySelector(".container>#zTree");// console.log(zTree);zTree.onclick = function (e) {if (e.target.tagName === "EM") {// console.log(e.target.classList.contains("open"));let siblingUl = e.target.nextElementSibling;// console.log([e.target], siblingUl);if (e.target.classList.contains("open")) {e.target.classList.remove("open");siblingUl.style.display = "none";// continue} else {e.target.classList.add("open");siblingUl.style.display = "block";}}};const getData = function getData() {const thePromise = new Promise((resolve, reject) => {let xhr = new XMLHttpRequest();xhr.open("GET", "./data.json", true);xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {let data = JSON.parse(xhr.response);// console.log(data);resolve(data);}};xhr.send();});return thePromise;};// getData();// getData()// .then((value) => {// console.log("方法一thePromise.then().catch()", value);// })// .catch((err) => {// console.log(err);// });// const render = async function render() {// try {// let data = await getData();// console.log("方法二async-await", data);// } catch (err) {// console.log(err, "执行中断");// }// };// render();const toLiListString = function toLiListString(liDataList) {let theString = ``;// console.log(liDataList);liDataList.forEach((item, index) => {console.log(item);let { name, children, open } = item;theString += `<li class="the-item"><a href="javascript:;" class="title">${name}</a>${children?.length? `<em class="icon ${open ? `open` : ``}"></em><ul class="level" style="display: ${open ? `block` : `none`}"><!-- <li class="the-item"><a href="javascript:;" class="title">第二级第一项</a></li> -->${toLiListString(children)}</ul>`: ``}</li>`;});return theString;};const render = async function render() {let data = await getData();const htmlString = toLiListString(data);zTree.innerHTML = htmlString;};render();})();
</script>
npm
npm就是包管理器。
npm安装
想要使用npm包管理器,就要先安装node.js。
到node.js官网上,下载稳定版。
下载好之后一直点击下一步,最好用默认方式,别乱改路径。
npm的作用
- 下载项目资源包
- 一般情况下,需要进入官方网站,下载对应的资源包,如swiper。
- 而npm就可以使用资源包的名称直接下载,不需要去官方网站。
- 不过下载下来的资源包,还需要进行管理。
- 管理项目资源包
- 基本概念
- 依赖清单 package.json
- devDependencies 服务器上已经没有了,在服务器打包时用不到的依赖
- 不过服务器环境将不可以使用它里面的依赖。
- dependencies 项目部署到服务器上用到的依赖
- 不过开发环境还也可以使用它里面的依赖。
- devDependencies 服务器上已经没有了,在服务器打包时用不到的依赖
- 资源包的仓库 node_modules
- 前提条件
- 文件夹不能含有中文,可能会造成一些错误。因为中文字符在window或一些服务器或一些包里,可能支持度不太好。
- 祖先文件夹 不能含有
node_modules
文件夹
- 前提条件
- 依赖清单 package.json
- 使用npm常用命令管理项目资源包
- 基本概念
常用命令
- 初始化,创建依赖清单
npm init -y//会在当前文件夹中创建package.json这个文件
常用依赖项管理命令
-
下载资源包
npm install 资源包名称 --save//完全 // npm install(简写:i) XXX (--save省略) // npm install XXX --save(简写:-S) npm i XXX npm i XXX -S
- 依赖清单记录到—》dependencies(生产环境)项目部署到服务器
- 下载的资料包会放到—》node_modules
-
下载资料包
npm install(简写:i) XXX --save-dev(简写:-D) npm i XXX -D
- 依赖清单记录到—》devDependencies(开发环境)本地自己开发的时候
- 下载的资料包会放到—》node_modules
-
删除资料包 npm uninstall(简写:uni) XXX
资料包的网站:https://www.npmjs.com/(国外网站),只要这个网站上含有的资料包都可以下载
-
安装指定版本
npm i XXX@3.6.2(版本号) -
查看版本号
npm view XXX versions
alpha 内测版{不稳定,有BUG}
beta 公测版
rc 最终测试版「和正式版差不多了」
stable 正式稳定版(不写)
-
最后一个稳定版
npm i XXX@latest -
最后一个即将发布版本(最后一个测试内测版本)
npm i XXX@next
全局安装
全局安装(前面的路径随意) :安装到你的电脑的某个位置(电脑规定的文件夹)
电脑上的任何文件都可以用
只能安装1个版本
本地安装(前面的路径自己规定的文件夹) :直接安装到自己规定文件夹
只能在当前文件夹里使用
可以安装多个版本(多个文件夹 1文件夹–版本1 2文件夹–版本2)
全局安装(前面的路径随意)
npm i xxx --global(简写: -g)
苹果电脑全局安装要加***** sudo
sudo npm i xxx -g 还有可能输入 密码
查看全局安装目录
npm root -g
删除全局安装
npm uni xxx --g
跑环境-安装依赖
git 下载的资料文件家中都不会含有 node_modules,又需要node_modules
*****跑环境:(依据 package.json)
npm i (开发环境和生产环境都跑下来)
npm i --production(只跑生产环境(dependencies))
npm的替代方案
1.下载加速(去国内站点下载)淘宝镜像
1.1使用淘宝镜像(下载cnpm)
npm install -g cnpm --registry=https://registry.npm.taobao.org
1.2使用cnpm(有可能有点小问题 丢包)
之后使用 cnpm 来代替 npm,----》cnpm和npm可以共存
2.下载加速(去国内站点下载)yarn*****
2.1 下载yarn npm i yarn -g
2.2 yarn init -y
2.3 yarn add XXX
yarn add xxx --dev 安装开发依赖
2.4 yarn remove XXX
yarn add/remove xxx/xxx@xxx/xxx@latest…
2.5跑环境
yarn install
yarn install --production
2.6全局安装
yarn global add xxx 很少用
还用yarn 要保证有 yarn.lock----》yarn install
终端窗口
cmd窗口常用命令
清屏:cls 苹果(clear)
ctrl+c(多次) —>y 中断命令
进阶参考
- node.js 官网 - 用来下载node.js的
- Node.js安装及环境配置之Windows篇
- npm官网 - 国外 - 查找资源包
- 详解从零创建自己的NPM包