vite和webpack區別
vite
vite使用原生ES模塊進行開發,無需在編譯時將所有代碼轉換為JS打包,從而提供了更快的熱更新和自動刷新功能;
vite在開發模式下沒有打包步驟,而是利用瀏覽器的ES Module Imports特性實現按需編譯,這種模式極大的提高了開發環境的相應速度,在生產模式下,vite使用Rollup進行打包,提供更好的tree-shaking和代碼壓縮。
由于ES Module需要高版本瀏覽器支持,所以本地編譯選用使用高版本瀏覽器
webpack
webpack擁有豐富的插件系統和高度可配置性,但由于全量的熱更新策略導致編譯速度慢;
webpack將所有模塊打包為一個或多個文件,初次加載速度較慢
webpack插件生態非常成熟,使得在大型復雜項目中具有很高的靈活性
webpack會先打包,然后啟動開發服務器,請求服務器時直接給予打包結果。而vite是直接啟動開發服務器,請求哪個模塊再對該模塊進行實時編譯。由于現代瀏覽器本身就支持ES Module,會自動向依賴的Module發出請求。vite充分利用這一點,將開發環境的模塊文件,就作為瀏覽器要執行的文件,而不是像webpack那樣進行打包合并。由于vite再啟動時候不需要打包,也就意味著不需要分析模塊的依賴、不需要編譯,因此啟動速度非常快。當瀏覽器請求某個模塊時候,再根據需要對模塊內容進行編譯。這種按需動態編譯的方式,極大的縮減了編譯的時間,項目越復雜、模塊越多、vite的優勢越明顯。
在HMR方面,當改動了一個模塊后,僅需讓瀏覽器重新請求該模塊即可,不像webapck那樣需要把該模塊的相關依賴模塊全部編譯一次,效率更高。
當需要打包到生產環境時,vite使用傳統的rollup進行打包,因此vite的主要優勢在開發階段,由于vite使用的是ES Module,因此在代碼中不可以使用CommonJS
watchEffect watch computed區別
- watchEffect
function watchEffect(/*要運行的副作用函數。用來注冊清理回調。清理回調會在該副作用的下一次執行前被調用,可以用來清理無效的副作用*/effect: (onCleanup: OnCleanup) => void,/*可以用來調整副作用的刷新時機或調試副作用的依賴。默認情況下,偵聽器在組件渲染之前執行,設置flust: 'post'將會使偵聽器延遲到組件渲染之后再執行。在某些特殊情況(列如要使緩存失效),可能有必要在響應式依賴放生改變時立即出發偵察器,可以使用flush: 'sync'當多個屬性同時更新時,這將會導致一些性能和數據一致性的問題*/options?: WatchEffectOptions
): StopHandletype OnCleanup = (cleanupFn: () => void) => voidinterface WatchEffectOptions {flush?: 'pre' | 'post' | 'sync' // 默認:'pre'onTrack?: (event: DebuggerEvent) => voidonTrigger?: (event: DebuggerEvent) => void
}type StopHandle = () => voidconst count = ref(0)
watchEffect(() => console.log(count.value))
// -> 輸出 0
count.value++
// -> 輸出 1// 副作用清除
watchEffect(async (onCleanup) => {const { response, cancel } = doAsyncWork(id.value)// `cancel` 會在 `id` 更改時調用// 以便取消之前// 未完成的請求onCleanup(cancel)data.value = await response
})//停止偵聽器:
const stop = watchEffect(() => {})// 當不再需要此偵聽器時:
stop()
- watch
- computed
vue3的效率提升主要表現在哪些方面
- 靜態提升
- 預字符串化
- 緩存事件處理函數
- PatchFlag
上圖中會對h1,h2標簽做靜態提升,在render函數外定義_hoisted_1,_hoisted_1 在render函數中可以重復使用;
當存在連續大量的(測試元素數量>10)靜態元素時候,vue3會進行預字符串化,通過_createStaticVNode生成字符串;
當有事件處理時vue3會讀取render中_cache緩存,而不需要每次都重新創建一個事件;
vue2中不會區分節點是動態的還是靜態的,需要層層比較,而vue3中會在_createElementVNode中對節點進行標記,動態節點標記為1,靜態節點標記為-1
_createElementVNode(type, props, children, patchFlag, dynamicChildren, shapeFlag, hooks, data){/**type:組件的構造函數、選項式組件的 VNode 數據對象或者 HTML 標簽字符串。props:一個對象,包含 (可能是 reactive 的) 屬性,這些屬性會被傳遞到組件。children:子 VNode 或者靜態內容的數組。patchFlag:用于優化渲染的標記位。dynamicChildren:動態子 VNode 的數組,用于動態 children。shapeFlag:標記 VNode 的形狀信息,比如是否是元素、文本、Fragment 等。hooks:生命周期鉤子對象。data:VNode 數據對象,包含了與平臺相關的屬性,比如 props、attrs、on。*/
}export const enum PatchFlags {TEXT = 1,// 1 動態的文本節點CLASS = 1 << 1, // 2 動態的 classSTYLE = 1 << 2, // 4 動態的 stylePROPS = 1 << 3, // 8 動態屬性,不包括類名和樣式FULL_PROPS = 1 << 4, // 16 動態 key,當 key 變化時需要完整的 diff 算法做比較HYDRATE_EVENTS = 1 << 5, // 32 表示帶有事件監聽器的節點STABLE_FRAGMENT = 1 << 6, // 64 一個不會改變子節點順序的 FragmentKEYED_FRAGMENT = 1 << 7, // 128 帶有 key 屬性的 FragmentUNKEYED_FRAGMENT = 1 << 8, // 256 子節點沒有 key 的 FragmentNEED_PATCH = 1 << 9, // 512 表示只需要non-props修補的元素 (non-props不知道怎么翻才恰當~)DYNAMIC_SLOTS = 1 << 10, // 1024 動態的soltDEV_ROOT_FRAGMENT = 1 << 11, //2048 表示僅因為用戶在模板的根級別放置注釋而創建的片段。 這是一個僅用于開發的標志,因為注釋在生產中被剝離。//以下兩個是特殊標記HOISTED = -1, // 表示已提升的靜態vnode,更新時調過整個子樹BAIL = -2 // 指示差異算法應該退出優化模式
}