首先我要說明一下,沒錯,還是沒有進入vue,劉備請諸葛亮三次都可以了吧,我這也是第三次了,也絕對是最後一次了,我應經摸透了因為,最後的webpack打包加上一個git學了過後我就去vue了。 為什麼要說先看這篇,其實跟我們今天的主題webpack沒有太大關係,昨天學了一下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作為一個區分