vue - ES6模块化、promise、webpack打包(所在在学的朋友们先看这篇,看了不吃亏)
首先我要说明一下,没错,还是没有进入vue,刘备请诸葛亮三次都可以了吧,我这也是第三次了,也绝对是最后一次了,我应经摸透了因为,最后的webpack打包加上一个git学了过后我就去vue了。
为什么要说先看这篇,其实跟我们今天的主题webpack没有太大关系,昨天学了一下webpack,其实内容没多少,webpack的内容无非就是参考文档去怎么做,然后最主要的js、html生成、css、字体图标、图片来打包包括开启一个webpack服务器。但是我们今天的主要内容,但是我要说的是比较重要的是,在学的朋友们,正在学包括后面在学的朋友们,作为一个程序员还在手写笔记吗?我也是昨天才知道手写笔记的就我一个,我都惊了,我那么大一本笔记本,又长又厚的,我都做了那么多了,居然现在才知道,属实太亏了,毕竟也是那个道理,如果后面工作不可能去翻书吧,优不优雅暂且不说,这耗费的时间就离谱虽然我自己做的笔记,我大概知道哪个知识点在哪一页。
那么既然不太推荐手写笔记了,那要用什么来做呢,程序员必备——Markdown!而他比较好的一款编辑器——Typora,昨天也花了一点时间了解了一下它有哪些功能哪些快捷键,确实这样做笔记方便查找,而且省时最主要的,我原来学内容可能内容没多少,但是也挺多的,满打满算都是一天的时间,反正现在有了这个,特别是代码部分,有时候我还要手写代码,这个直接一个截图的事情,你可以自己想想节省了多少时间。
至于我以前在笔记本上的,我的打算是,暴力一点,直接全 背 下 来。
1.
回到我们今天的主题上来,首先第一个内容说一下vue的前提基础,首先es6的模块化,首先知道commanjs吧,是我们node的规则,require、exports都是他的语法,但他不是标准推荐的,真正的正统标准是ES6模块化,而且commanjs只支持后端,而es6支持前后端。
他的一个语法规则:
1.1
导入为import 暴露共享成员export 没有了s
如果我们node.js要使用es6模块化的话首先版本号是要大于14.15.1的,其次需要在package.json添加“type”:“module”
关于他的导入导出一共有两大类,第一类是默认导入导出。
export default 和 import 自定义 from ‘路径’ 注意路径必须添加后缀js跟我们的commanjs不一样
let x = 19 let y = 29 function show() {} export default { x, show }
import m1 from './默认导出.js'
console.log(m1);
然后按需导出 export const a = 1 就是谁要导出就在定义它的前面加一个export
按需导入 import {a} from ‘’ 这个要注意的是花括号里面的名字不再自定义必须和我们导出的一致,但是我们可以用as重命名
export let x = 10 export function show() {console.log('hello vue');}
import {x, show} from './按需导出.js'
console.log(x, show);
最后是我们的直接导入,直接导入其实也挺常用比如css,或者js直接就是一段代码,可以直接导入进来不使用,他们自己有自己的用处
for(let i = 0; i < 5; i++) { console.log(i); }
import './直接导入代码.js'
有一说一,这个代码块跟typora一样,看来这一步棋走对了。
2.
然后看到我们的promise这个构造函数
2.1
先了解一下回调地狱的问题吧,什么叫做回调地狱,就是我们多层嵌套回调函数,本身就是回调函数,还一层一层嵌套,他执行了才去执行里面的,其实也就是我们的高阶函数,那么这个时候就有问题了,我们要改上面的代码后面也要跟着改,而且大量冗余的代码可读性也差。
2.2
然后说回到我们的promise,没错它本身是个构造函数,然后他的prototype上面有一个.then的方法,所以他的实例是可以用的,这个.then是个什么方法,他就是用来预先指定成功或者失败的回调函数的,成功是必选参数,失败是可选。
比如我们下面通过一个案例来说,基于回调来读取内容,一个文件夹下面三个txt,以前的做法不用多说了的通过fs读完一个又在里面嵌套一个,这就是典型的回调地狱。
我们的fs模块不支持promise的方法所以我们需要下载一个包then-fs
import thenfs from 'then-fs' thenfs.readFile('./files/1.txt', 'utf-8').then((r1) => console.log(r1)) thenfs.readFile('./files/2.txt', 'utf-8').then((r2) => console.log(r2)) thenfs.readFile('./files/3.txt', 'utf-8').then((r3) => console.log(r3))
可以看到通过promise的方法能够输出出来,但是有一个问题顺序不太对,这里是因为异步的原因,后面会说到
2.3
先来解决我们的顺序问题,怎么样可以让他们按照顺序来呢?
想通一件事情,我们的thenfs读取出来是一个promise的实例对象所以我们才能在后面用then这个方法,如果我们在成功的回到函数里先输出然后返回下一个promise实例对象呢?
import thenfs from 'then-fs' thenfs.readFile('./files/1.txt', 'utf8').then((r1) => { console.log(r1); return thenfs.readFile('./files/2.txt', 'utf8') }).then((r2) => { console.log(r2); return thenfs.readFile('./files/3.txt', 'utf8') }).then((r3) => console.log(r3))
2.4
捕获错误
我们promise有一个捕获错误的方法,防止前面因为什么东西发生错误,而导致整盘崩溃,当然如果你大概知道是哪里可能有点问题也可以吧这个方法前移,那么这样就会继续执行后面的
import thenfs from 'then-fs' /* thenfs.readFile('./files/11.txt', 'utf-8').then((r1) => { console.log(r1); return thenfs.readFile('./files/2.txt', 'utf-8') //这里不做失败的回调函数,当我们成功后是不是又通过return反悔了一个thenfs创造的promise的实例对象 }).then((r2) => { console.log(r2); return thenfs.readFile('./files/3.txt', 'utf-8') }).then((r3) => { console.log(r3); }).catch((err) => { console.log(err.message); }) */ thenfs.readFile('./files/11.txt', 'utf-8') .catch((err) => { console.log(err.message); }) .then((r1) => { console.log(r1); return thenfs.readFile('./files/2.txt', 'utf-8') //这里不做失败的回调函数,当我们成功后是不是又通过return反悔了一个thenfs创造的promise的实例对象 }) .then((r2) => { console.log(r2); return thenfs.readFile('./files/3.txt', 'utf-8') }) .then((r3) => { console.log(r3); })
2.5
promise.all方法这是用来发起并行的异步操作的,什么意思,就是一个等待机制,多个异步操作,等待他们全部完成才会去执行then里面的函数
import thenfs from 'then-fs' let arr =[ thenfs.readFile('./files/1.txt', 'utf-8'), thenfs.readFile('./files/2.txt', 'utf-8'), thenfs.readFile('./files/3.txt', 'utf-8') ] Promise.all(arr).then((r) => console.log(r))
注意输出为一个数组,并且输出顺序使我们数组里面的执行顺序。
与之对应的还有一个promise.race方法,他与all一起都是发起并行操作,但是他是一旦有人执行完,就输出,意思就是最快的那一个
2.6
来一个案例,封装一个promise获取文件的函数,这个函数最主要的是要搞懂我们的回调与then之间这的关系,return 一个 new promise创造一个实例,而他只是形式上的promise实例对象,还需要往里面添加一个函数,这个函数两个参数就是用来接受then的两个成功和失败的函数,所以这两个参数是函数,再在里面来读取,fs的操作步骤,也有失败和结果去把结果给到刚才对应的两个参数
import fs from 'fs' function getTxt(Fpath,type) { return new Promise(function(suc, wro) { fs.readFile(Fpath, type, (err, result) => { if(err) return wro(err.message) suc(result) }) }) } getTxt('./files/1.txt', 'utf8').then((r1) => { console.log(r1) },(err) => { console.log(err) })
2.7
简化异步操作 。
刚才我们的不管是all方法还是按顺序执行的函数是不是都是为了能让我们的异步操作能按照顺序执行出来,下面是不仅执行了异步操作而且还能按照顺序执行出来的简化步骤用到await、async
import thenfs from 'then-fs' async function getFile() { const r1 = await thenfs.readFile('../promise/files/1.txt', 'utf-8') console.log(r1); const r2 = await thenfs.readFile('../promise/files/2.txt', 'utf-8') console.log(r2); const r3 = await thenfs.readFile('../promise/files/3.txt', 'utf-8') console.log(r3); } getFile()
function中用到await,函数就必须被async修饰。
不加await就是promise实例,加了就能返回值直接输出。
在await第一个之前是同步输出,后面都为异步任务
import thenfs from 'then-fs' console.log('A'); async function getFile() { console.log('B') const r1 = await thenfs.readFile('../promise/files/1.txt', 'utf-8') const r2 = await thenfs.readFile('../promise/files/2.txt', 'utf-8') const r3 = await thenfs.readFile('../promise/files/3.txt', 'utf-8') console.log(r1,r2,r3); console.log('D'); } getFile() console.log('C');
这个你认为输出出来是多少?
ABCr123最后D
3.
事件流,时间循环我自己口述一遍吧,之前也说过的,我们的任务分为同步任务和异步任务,同步任务会优先在主栈道上执行完,异步任务会根据宿主环境在那里执行,但是异步任务都是有回调函数的,所以执行了就会把函数放到异步任务的排列队伍,等到同步任务执行完,就会来按照顺序执行异步任务。
3.1
js又把异步任务进一步划分了宏任务和微任务。
宏任务:比如ajax、计时器、文件操作等
微任务:promise那几个方法、prcess.nextTick等
在异步任务中会优先执行宏任务再去检查这个宏任务里面的微任务,然后再去执行宏任务这样一个循环,来看一个经典面试题,你看输出的什么?
console.log('1'); setTimeout(() => { console.log('2'); new Promise (function(resolve) { console.log('3'); resolve() }).then(function() { console.log('4'); }) }); new Promise(function(resolve) { console.log('5'); resolve() }).then(function() { console.log('6'); }) setTimeout(() => { console.log('7'); new Promise (function(resolve) { console.log('8'); resolve() }).then(function() { console.log('9'); }) });
正确答案:156234789
这个最大的难点我觉得在于当我们进入一个作用域后,会是一个全新的作用域,在这个里面再去重新看待里面的一些任务,就相当于你现在在这个作用域里面就是全局作用域
4.
进入webpack。
webpack本质上是一个第三方模块包,他可以起到压缩、翻译、打包、降级的作用。
webpack环境准备:
yarn init 初始化
yarn add webpack
在package里面添加执行命令“build” :“webpack”
反正webpack始终要记住一点他只支持js,其他的都需要去文档上看怎么转过来。
而且他的操作也比较规律化,先定义好文件,css要有css文件,字体图标要有字体图标文件,然后要跟我们的入口文件挂上钩,像img图片、字体图标这些需要动态创建在入口文件里面,css直接导入,包括更改默认出入口,加载器、插件这些都是在webpack.config.js这个配置文件里面改。
另外的注意点就是我们的图片处理只针对于img标签,背景图片会被css解析的,但是最好还是要做图片处理,因为如果type为asset的话,会以8kb作为一个区分