2025前端面試遇到的問題(vue+uniapp+js+css)

Vue相關面試題

vue2和vue3的區別

一、核心架構差異

特性Vue2Vue3
響應式系統基于Object.defineProperty基于Proxy(支持動態新增/刪除屬性)
代碼組織方式Options API(data/methods分塊)Composition API(邏輯按功能聚合)
虛擬DOM優化全量對比靜態標記(Patch Flags)、靜態提升
Tree-shaking支持按需編譯,體積更小(如無用的功能模塊可剔除)

二、核心特性對比詳解

1.?響應式系統
  • Vue2
    通過Object.defineProperty劫持對象屬性的getter/setter,但無法檢測數組索引修改對象屬性新增/刪除,需用Vue.set/Vue.delete

    // Vue2中動態添加響應式屬性
    Vue.set(this.obj, 'newKey', 'value');
  • Vue3
    使用Proxy代理整個對象,天然支持深層響應式,無需額外API。

    const reactiveObj = reactive({});
    reactiveObj.newKey = 'value'; // 自動觸發響應
2.?代碼組織方式
  • Vue2 Options API
    邏輯分散在datamethodscomputed等選項中,復雜組件代碼閱讀困難。

    export default {data() { return { count: 0 } },methods: { increment() { this.count++ } }
    }
  • Vue3 Composition API
    使用setup()函數聚合邏輯,支持邏輯復用(類似React Hooks)。

    import { ref } from 'vue';
    export default {setup() {const count = ref(0);const increment = () => count.value++;return { count, increment };}
    }
3.?性能優化
  • 虛擬DOM Diff優化
    Vue3通過Block TreePatch Flags標記動態節點,減少對比范圍。

    // Vue3模板編譯后生成的虛擬DOM片段
    createVNode("div", { id: "foo" }, [createVNode("span", { class: _ctx.dynamicClass }, null, 1 /* CLASS */)
    ]);
  • Tree-shaking
    Vue3模塊化設計,未使用的功能(如v-model修飾符)不會打包進最終產物。

三、新特性與開發體驗

特性Vue2Vue3
Fragment支持單根節點組件支持多根節點(減少無意義包裹)
Teleport組件跨DOM層級渲染(如全局彈窗)
Suspense組件異步組件加載狀態管理
TypeScript支持需額外類型聲明源碼使用TS編寫,原生支持更完善

四、生命周期與API變化

Vue2生命周期Vue3生命周期說明
beforeCreate使用setup()替代setup()中執行初始化邏輯
created使用setup()替代
beforeMountonBeforeMount組合式API鉤子需顯式引入
mountedonMounted
beforeDestroyonBeforeUnmount命名更語義化
destroyedonUnmounted

五、遷移注意事項

  1. 全局API變化

    • Vue.prototype?→?app.config.globalProperties

    • new Vue()?→?createApp()

    // Vue3創建應用實例
    import { createApp } from 'vue';
    const app = createApp(App);
    app.mount('#app');
  2. 事件總線替代
    Vue3移除$on/$off,推薦使用mitt等第三方庫。

  3. 過濾器(Filters)廢棄
    改用計算屬性或方法處理數據格式化。

六、總結回答示例

"Vue3的核心升級集中在響應式系統重構(Proxy替代defineProperty)、開發體驗優化(Composition API聚合邏輯)、性能提升(Tree-shaking、虛擬DOM優化)以及新特性支持(Fragment、Teleport等)。
例如,在Vue2中處理動態新增響應式屬性需要Vue.set,而Vue3的Proxy機制讓這變得自然。同時,Composition API讓復雜組件的邏輯更易維護。
這些改進使Vue3更適合大型項目,同時保持對Vue2的漸進式兼容。"

加分項

  • 提及Vue3的<script setup>語法糖(更簡潔的組合式API寫法)。

  • 對比生態工具(如Vue Router 4、Pinia替代Vuex)。

  • 性能數據:Vue3打包體積減少41%,渲染速度提升55%。

compted和watch的區別

在Vue.js中,computedwatch都是用于響應數據變化的工具,但它們的應用場景和實現邏輯有本質區別。以下是它們的核心差異和適用場景:

一、核心區別

特性computedwatch
目的聲明式依賴追蹤,生成新值監聽數據變化,執行副作用操作
緩存有緩存(依賴不變時直接返回緩存值)無緩存(每次變化都觸發回調)
同步/異步必須同步返回結果支持異步操作
適用場景模板中需要動態計算的派生數據數據變化時需要觸發復雜邏輯(如API請求)
語法定義為一個函數(可含getter/setter)監聽一個或多個數據源,定義handler函數

二、工作機制詳解

1.?computed(計算屬性)
  • 依賴追蹤:自動追蹤其內部依賴的響應式數據,依賴變化時重新計算。

  • 緩存機制:只有依賴變化時才會重新計算,否則直接返回緩存值。

  • 語法示例

    export default {data() {return { firstName: '張', lastName: '三' }},computed: {fullName() {return this.firstName + ' ' + this.lastName; // 依賴firstName和lastName}}
    }

    模板中使用

    <template><div>{{ fullName }}</div> <!-- 自動更新 -->
    </template>
2.?watch(偵聽器)
  • 主動監聽:顯式指定要監聽的數據源(可以是簡單路徑或復雜表達式)。

  • 回調觸發:數據變化時執行回調函數,適合處理異步或耗時操作。

  • 語法示例

    export default {data() {return { searchKeyword: '' }},watch: {// 監聽searchKeyword變化searchKeyword(newVal, oldVal) {this.fetchSearchResults(newVal); // 觸發搜索邏輯(可能是異步的)}}
    }

三、使用場景對比

使用computed的場景
  • 動態計算顯示值
    例如:根據單價和數量計算總價、格式化日期、過濾列表等。

    computed: {totalPrice() {return this.quantity * this.unitPrice;}
    }
  • 依賴多個值的復雜邏輯

    //根據用戶權限和頁面狀態動態顯示按鈕。computed: {showAdminButton() {return this.user.role === 'admin' && this.pageStatus === 'edit';}
    }
使用watch的場景
  • 數據變化觸發副作用
    例如:搜索框輸入變化時發起API請求。

    watch: {searchKeyword(newVal) {if (newVal) {this.debouncedSearch(newVal); // 防抖搜索}}
    }
  • 監聽引用類型的變化(需深度監聽):
    例如:監聽對象或數組內部變化。

    watch: {userInfo: {handler(newVal) {console.log('用戶信息變化:', newVal);},deep: true // 深度監聽}
    }
  • 異步操作
    例如:數據變化后需要延遲執行或調用外部接口。

    watch: {async userId(newVal) {const data = await fetchUserData(newVal);this.userData = data;}
    }

四、高級用法

1.?computed的Setter

允許通過賦值操作反向修改依賴數據:

computed: {fullName: {get() {return this.firstName + ' ' + this.lastName;},set(newValue) {const [firstName, lastName] = newValue.split(' ');this.firstName = firstName;this.lastName = lastName;}}
}
2.?watch的高級配置
  • immediate: true:組件初始化時立即執行回調。

  • deep: true:深度監聽對象/數組內部變化。

  • 監聽多個數據源

    watch: {'obj.a'(newVal) { /* 監聽嵌套屬性 */ },'arr.0': { handler() { /* 監聽數組索引 */ } }
    }

五、性能優化建議

  1. 優先使用computed
    需要派生新值時,computed的緩存機制能減少不必要的計算。

  2. 避免濫用watch
    監聽大量數據或頻繁觸發的操作可能導致性能問題。

  3. 復雜計算拆分
    將大型計算屬性拆分為多個小計算屬性,提高可維護性和緩存效率。

六、總結

  • computed:適合依賴其他數據生成新值的場景(如動態計算、格式化),利用緩存優化性能。

  • watch:適合響應數據變化執行操作的場景(如API請求、日志記錄),支持異步和深度監聽。

錯誤用法示例

// ? 錯誤:用watch實現本該由computed完成的功能
watch: {firstName() { this.fullName = this.firstName + this.lastName; },lastName() { this.fullName = this.firstName + this.lastName; }
}
// ? 正確:用computed自動追蹤依賴
computed: {fullName() { return this.firstName + this.lastName; }
}

虛擬DOM是什么?

在 Vue 中,虛擬 DOM(Virtual DOM)?是一種用于優化頁面渲染性能的核心技術,它是真實 DOM 的輕量級 JavaScript 對象表示。Vue 通過虛擬 DOM 實現高效的差異化更新,從而減少對真實 DOM 的直接操作,提升應用性能。


一、虛擬 DOM 的核心作用

1.?性能優化
  • 直接操作 DOM 成本高:每次 DOM 修改都會觸發瀏覽器重排(Reflow)和重繪(Repaint)。

  • 虛擬 DOM 的緩沖機制:通過對比新舊虛擬 DOM 的差異(Diff 算法),僅更新必要的 DOM 節點。

2.?簡化開發
  • 聲明式編程:開發者只需關注數據變化,無需手動操作 DOM。

  • 跨平臺能力:虛擬 DOM 可映射到不同平臺(如瀏覽器、小程序、原生應用)。


二、Vue 中虛擬 DOM 的工作流程

1.?模板編譯

Vue 將模板(.vue?文件或?template?字符串)編譯為渲染函數(Render Function):

// 模板
<div id="app">{{ message }}</div>// 編譯后的渲染函數
function render() {return _c('div', { attrs: { id: 'app' } }, [_v(_s(message))])
}
2.?生成虛擬 DOM

執行渲染函數,生成描述 DOM 結構的虛擬節點(VNode):

const vnode = {tag: 'div',data: { attrs: { id: 'app' } },children: [ { text: 'Hello Vue!' } ]
}
3.?響應式數據觸發更新

當數據(如?message)變化時,Vue 的響應式系統會觸發組件重新渲染,生成新的虛擬 DOM 樹

4.?Diff 算法對比差異

Vue 的 Diff 算法(稱為?patch 過程)對比新舊虛擬 DOM 樹:

  • 同級比較:僅對比同一層級的節點。

  • Key 優化:通過?key?標識節點身份,避免列表渲染錯誤。

// 舊虛擬 DOM
{ tag: 'div', children: [ { text: 'Old' } ] }// 新虛擬 DOM
{ tag: 'div', children: [ { text: 'New' } ] }// Diff 結果:僅更新文本節點
5.?更新真實 DOM

根據 Diff 結果,調用原生 DOM API 進行最小化更新:

// 偽代碼示例
if (oldVNode.text !== newVNode.text) {textNode.nodeValue = newVNode.text; // 僅修改文本內容
}

三、虛擬 DOM 的關鍵優勢

優勢說明
批量更新合并多次數據變更,避免頻繁 DOM 操作
差異更新僅更新變化的部分,減少重排重繪次數
跨平臺渲染同一套虛擬 DOM 可渲染到瀏覽器、Native(Weex)、Canvas(如圖表庫)等
開發體驗優化無需手動操作 DOM,專注于數據邏輯

四、虛擬 DOM 的局限性

局限性說明
內存占用需維護虛擬 DOM 樹,內存開銷略高
首次渲染耗時需額外生成虛擬 DOM,首次加載可能稍慢
極端性能場景對性能要求極高的動畫/游戲,仍需直接操作 DOM

五、示例:Vue 中虛擬 DOM 的實際應用

<template><div><button @click="count++">Click {{ count }}</button><ul><li v-for="item in list" :key="item.id">{{ item.text }}</li></ul></div>
</template><script>
export default {data() {return {count: 0,list: [{ id: 1, text: 'A' },{ id: 2, text: 'B' }]};}
};
</script>
更新過程解析:
  1. 點擊按鈕count?自增,觸發重新渲染。

  2. 生成新虛擬 DOM:Vue 調用渲染函數生成新的虛擬 DOM 樹。

  3. Diff 對比

    • <button>?的文本節點變化。

    • <li>?列表因?key?存在,高效復用 DOM 節點。

  4. Patch 更新:僅修改按鈕文本,列表無需變動。


六、如何優化 Vue 的虛擬 DOM 性能

  1. 合理使用?key

    <!-- 使用唯一標識 key -->
    <li v-for="item in list" :key="item.id">{{ item.text }}</li>
  2. 避免不必要的渲染

    • 使用?v-once?靜態標記:

      <div v-once>{{ staticContent }}</div>
    • 使用?shouldComponentUpdate(Vue 的?shouldUpdate?鉤子)。

  3. 減少模板復雜度

    • 拆分復雜組件,避免過深的虛擬 DOM 樹。


七、舉個例子,讓你輕松理解虛擬 DOM 是什么,以及它在 Vue 中為什么重要?


虛擬 DOM 就像「建筑模型」

想象你要裝修房子,直接裝修成本很高(每次改個插座都要砸墻),于是你做了個?「房屋模型」(虛擬 DOM)來模擬真實房子(真實 DOM)。每次改動都先在模型上調整,最后只按模型修改真實房子。


為什么用虛擬 DOM?
1. 避免「拆了又建」的浪費
  • 直接操作 DOM:相當于每次改動都拆掉房子重建(比如改個燈泡,卻把整個房子拆了再蓋)。

  • 用虛擬 DOM:先在模型上改好(比如換個燈泡位置),對比新舊模型,只拆換燈泡的位置,其他部分保留。

2. 提高「裝修效率」
  • 設計師(Vue)的工作流程

    1. 畫草圖(生成虛擬 DOM)
      先畫個裝修設計圖(描述房子該長什么樣)。

    2. 對比修改(Diff 算法)
      如果之前有舊設計圖,就對比哪里需要改(比如墻面顏色變了,但地板沒變)。

    3. 按圖施工(更新真實 DOM)
      只刷墻,不換地板,省時省力。


舉個具體例子

假設你有一個待辦清單:

<ul><li>買菜</li><li>做飯</li>
</ul>
直接操作 DOM(原始方法)
  • 添加一個新任務「洗碗」:

    • 刪掉整個?<ul>

    • 重新創建?<ul>?并插入所有?<li>(包括已有的和新增的)

用虛擬 DOM(Vue 的方法)
  1. 生成新虛擬 DOM

    // 舊虛擬 DOM
    { tag: 'ul', children: [{ tag: 'li', text: '買菜' },{ tag: 'li', text: '做飯' }
    ]}// 新虛擬 DOM(添加「洗碗」)
    { tag: 'ul', children: [{ tag: 'li', text: '買菜' },{ tag: 'li', text: '做飯' },{ tag: 'li', text: '洗碗' }
    ]}
  2. 對比差異(Diff 算法)

    • 發現只是多了一個?<li>洗碗</li>

  3. 只添加新節點

    • 真實 DOM 中只插入新?<li>,其他不變。


虛擬 DOM 的三大好處
好處例子說明
加快速度改燈泡不用拆房子
減少卡頓避免頁面頻繁閃爍(只改必要的部分)
自動處理復雜邏輯你只管說「要加洗碗」,Vue 自動找最優修改方式

為什么需要「Key」?

如果任務列表是動態的(比如順序會變),Vue 需要一個「身份證號」(Key)來識別每個任務,避免誤判。比如:

<!-- 沒有 Key 的情況 -->
<li>任務A</li>
<li>任務B</li><!-- 插入新任務后可能出錯 -->
<li>任務C</li> <!-- Vue 可能誤以為這是任務A,導致渲染錯誤 -->
<li>任務A</li>
<li>任務B</li><!-- 用 Key 解決 -->
<li key="1">任務A</li>
<li key="2">任務B</li><!-- 插入新任務后 -->
<li key="3">任務C</li> <!-- Vue 通過 Key 知道這是新增的 -->
<li key="1">任務A</li>
<li key="2">任務B</li>

總結

  • 虛擬 DOM 的本質:一個輕量版的「房屋模型」,用來模擬真實頁面結構。

  • Vue 的工作方式:先改模型 → 對比變化 → 只改真實頁面需要動的地方。

  • 你的好處:不用操心怎么操作 DOM,專注寫業務邏輯,Vue 自動幫你高效更新頁面!

下次寫 Vue 時,可以想象自己是在「畫設計圖」,而 Vue 是那個「高效施工隊」! 🛠?

vue項目內多個請求如何讓頁面不卡頓

在Vue項目中處理多個請求時保持頁面流暢,需要從?請求控制渲染優化?和?交互設計?三個維度進行優化。以下是具體方案:


一、請求控制優化

1. 分批次并發請求(避免一次性全量請求)
// 關鍵數據優先請求
async function loadCriticalData() {const [user, config] = await Promise.all([fetch('/api/user'),fetch('/api/config')]);// 渲染核心內容
}// 非關鍵數據延遲加載
setTimeout(() => {fetch('/api/additional-data')
}, 2000);
2. 請求優先級隊列
class RequestQueue {constructor(maxConcurrent = 3) {this.queue = [];this.activeCount = 0;this.maxConcurrent = maxConcurrent;}add(requestFn) {return new Promise((resolve, reject) => {this.queue.push({ requestFn, resolve, reject });this.next();});}next() {while (this.activeCount < this.maxConcurrent && this.queue.length) {const { requestFn, resolve, reject } = this.queue.shift();this.activeCount++;requestFn().then(resolve).catch(reject).finally(() => {this.activeCount--;this.next();});}}
}// 使用示例
const queue = new RequestQueue(4); // 最大并發4個
queue.add(() => fetch('/api/data1'));
queue.add(() => fetch('/api/data2'));

二、渲染性能優化

1. 虛擬滾動(大數據列表)
<template><!-- 使用vue-virtual-scroller --><RecycleScrollerclass="scroller":items="bigDataList":item-size="50"key-field="id"><template v-slot="{ item }"><div class="item">{{ item.name }}</div></template></RecycleScroller>
</template>
2. 分塊渲染
// 分批處理大數據
function chunkRender(data) {let index = 0;const chunkSize = 50;function doChunk() {const chunk = data.slice(index, index + chunkSize);this.items.push(...chunk);index += chunkSize;if (index < data.length) {requestIdleCallback(doChunk); // 利用空閑時間渲染}}requestIdleCallback(doChunk);
}
3. 凍結非活躍數據
// 使用Object.freeze避免響應式追蹤
this.bigData = Object.freeze(rawData);

三、交互體驗優化

1. 骨架屏占位
<template><div v-if="loading" class="skeleton"><div class="skeleton-item"></div><div class="skeleton-item"></div></div><div v-else>...</div>
</template><style>
.skeleton-item {background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);animation: shimmer 1.5s infinite;
}@keyframes shimmer {100% { background-position: -200% 0; }
}
</style>
2. 請求取消
// 使用axios CancelToken
const source = axios.CancelToken.source();fetchData() {axios.get('/api/data', {cancelToken: source.token}).catch(thrown => {if (axios.isCancel(thrown)) {console.log('請求被取消', thrown.message);}});
}// 組件銷毀時取消請求
beforeDestroy() {source.cancel('組件卸載取消請求');
}

四、性能監測與調試

1. Chrome Performance分析
// 添加性能標記
window.performance.mark('fetchStart');
await fetchData();
window.performance.mark('fetchEnd');
window.performance.measure('數據請求', 'fetchStart', 'fetchEnd');
2. 長任務檢測
const observer = new PerformanceObserver((list) => {for (const entry of list.getEntries()) {console.log('[長任務]', entry);}
});
observer.observe({ entryTypes: ['longtask'] });

五、進階優化方案

方案適用場景實現方式
Web Worker復雜數據處理將數據計算移出主線程
HTTP/2 Server Push高并發請求服務端主動推送資源
請求緩存重復數據獲取內存緩存 + LocalStorage
Tree Shaking減少打包體積配置Vue CLI的優化項

六、優化前后性能對比

指標優化前優化后
主線程阻塞時間1200ms300ms
首次內容渲染2.5s800ms
內存占用150MB80MB

通過?請求并發控制?+?渲染策略優化?+?交互反饋設計?的組合拳,可有效解決多請求場景下的頁面卡頓問題。建議根據實際場景選擇2-3個關鍵優化點組合實施。


本地緩存有哪些?有哪些區別?

在Web開發中,常見的本地緩存技術包括?Cookie、Web Storage(LocalStorage/SessionStorage)、IndexedDB、Cache API?等。以下是它們的核心區別及適用場景:


一、本地緩存技術對比

技術存儲容量生命周期數據格式訪問方式適用場景特點
Cookie~4KB可設置過期時間(默認會話級)字符串鍵值對同步用戶會話管理、服務端通信(如Token)每次請求自動攜帶,需注意安全性
LocalStorage5MB~10MB(瀏覽器)永久存儲(需手動清除)字符串鍵值對同步長期存儲用戶偏好、離線數據簡單易用,無自動過期機制
SessionStorage5MB~10MB(瀏覽器)會話級(標簽頁關閉即清除)字符串鍵值對同步臨時存儲表單數據、頁面間傳參數據隔離性強(按標簽頁隔離)
IndexedDB無硬性限制(通常≥250MB)永久存儲(需手動清除)結構化數據(對象存儲)異步復雜數據管理(如離線應用、大數據緩存)支持事務、索引、查詢
Cache API動態分配(通常≥50MB)隨Service Worker生命周期網絡請求/響應異步緩存靜態資源(PWA離線支持)精準控制資源緩存策略

二、技術詳解與典型應用

1.?Cookie
  • 核心特性

    • 自動隨HTTP請求發送到服務端(通過Cookie請求頭)

    • 通過document.cookie讀寫,需手動處理字符串分割

    • 必須設置SameSite屬性防止CSRF攻擊

  • 適用場景

    • 用戶登錄狀態保持(JWT Token)

    • 簡單的用戶偏好記錄(如主題選擇)

  • 示例

    // 設置Cookie(有效期7天)
    document.cookie = "theme=dark; max-age=604800; path=/; Secure";
2.?Web Storage
  • LocalStorage

    • 長期存儲:用戶語言設置、購物車數據持久化

    • 代碼示例

      localStorage.setItem('userSettings', JSON.stringify({ theme: 'dark' }));
      const settings = JSON.parse(localStorage.getItem('userSettings'));
  • SessionStorage

    • 臨時存儲:多步驟表單數據暫存、頁面間參數傳遞

    • 代碼示例

      sessionStorage.setItem('formStep1', JSON.stringify({ name: 'Alice' }));
3.?IndexedDB
  • 核心能力

    • 支持事務(Transaction)保證數據一致性

    • 可創建索引加速查詢

    • 存儲二進制數據(如圖片、文件)

  • 適用場景

    • 離線應用(如文檔編輯器)

    • 大數據量緩存(如本地日志存儲)

  • 代碼示例

    const request = indexedDB.open('myDB', 1);
    request.onsuccess = (e) => {const db = e.target.result;const tx = db.transaction('users', 'readwrite');const store = tx.objectStore('users');store.add({ id: 1, name: 'Alice' });
    };
     
4.?Cache API
  • 核心機制

    • 與Service Worker配合實現離線訪問

    • 按需緩存網絡請求,支持版本管理

  • 適用場景

    • PWA應用的靜態資源緩存

    • 動態內容離線訪問(如新聞詳情頁)

  • 代碼示例

    caches.open('v1').then(cache => {cache.addAll(['/styles.css', '/app.js']);
    });

三、選型建議

需求場景推薦方案原因
用戶登錄狀態管理Cookie(HttpOnly + Secure)自動攜帶至服務端,配合服務端驗證安全可靠
長期保存用戶主題偏好LocalStorage簡單鍵值對,持久化存儲
復雜數據查詢(如本地數據庫)IndexedDB支持索引、事務,適合結構化數據
離線優先的Web應用Cache API + Service Worker精準控制資源緩存策略,提升離線體驗
臨時存儲頁面間參數SessionStorage會話級隔離,避免數據污染

四、安全注意事項

  1. 敏感信息:避免在Cookie/LocalStorage存儲密碼等機密數據

  2. 容量限制:LocalStorage超過5MB可能觸發瀏覽器警告

  3. 數據清理:定期清理過期緩存(如通過TTL機制)

  4. 加密存儲:對敏感數據使用AES加密后再存儲


通過合理選擇本地緩存技術,可顯著提升Web應用的性能、離線能力和用戶體驗。


JS相關面試題

防抖和節流的區別?應該如何去做?

使用防抖(Debounce)和節流(Throttle)是優化高頻事件處理的常用手段。

一、防抖和節流的區別

防抖(Debounce)節流(Throttle)
觸發邏輯事件停止觸發后延遲執行固定時間間隔內最多執行一次
類比場景電梯門(最后一個人進入后關門)水龍頭(穩定間隔滴水)
適用場景輸入框搜索聯想、窗口resize監聽滾動加載、按鈕防重復點擊
執行次數高頻觸發時只執行最后一次高頻觸發時均勻執行

二、防抖和節流分別實現的方法

// 防抖實現
function debounce(fn, delay = 500) {let timer = null;return function(...args) {if (timer) clearTimeout(timer);timer = setTimeout(() => {fn.apply(this, args);}, delay);};
}// 節流實現
function throttle(fn, interval = 200) {let lastTime = 0;return function(...args) {const now = Date.now();if (now - lastTime >= interval) {fn.apply(this, args);lastTime = now;}};
}

三、防抖和節流選擇原則

  • 需要即時響應但避免過量請求用防抖(如搜索建議)

  • 需要保持操作連貫性用節流(如無限滾動加載)

?js原生input和on-change的區別

在原生 JavaScript 中,input?事件和?change?事件是表單元素(如?<input><select><textarea>)的兩種不同行為的事件,它們的核心區別在于觸發時機應用場景。以下是詳細對比:


一、input?事件與?change?事件的區別

特性input?事件change?事件
觸發時機值變化時實時觸發(如每次鍵盤輸入)失去焦點且值變化后觸發
適用場景實時搜索、輸入校驗表單提交前校驗、值最終確認
兼容性現代瀏覽器支持所有瀏覽器支持
響應速度高頻觸發(需防抖優化)低頻觸發

二、代碼示例對比

<input type="text" id="inputDemo"><script>const inputEl = document.getElementById('inputDemo');// input 事件:每次輸入都觸發inputEl.addEventListener('input', (e) => {console.log('input 事件:', e.target.value); // 實時輸出當前值});// change 事件:失焦且值變化時觸發inputEl.addEventListener('change', (e) => {console.log('change 事件:', e.target.value); // 僅失焦后輸出最終值});
</script>

測試步驟

  1. 在輸入框輸入 "hello"(每次按鍵都會觸發?input?事件)。

  2. 點擊頁面其他區域讓輸入框失焦,觸發?change?事件。

  3. 再次聚焦輸入框,不修改內容直接失焦,不會觸發?change?事件(值未變化)。


三、總結

  • input?vs?change

    • 需要實時反饋(如搜索聯想)用?input?+ 防抖。

    • 需要最終確認(如表單提交)用?change

異步請求有哪些方法?

一、XMLHttpRequest (原生)

底層API,所有現代異步請求的基礎

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data');// 狀態監聽
xhr.onreadystatechange = function() {if (xhr.readyState === 4) { // 請求完成if (xhr.status === 200) {console.log(JSON.parse(xhr.responseText));} else {console.error('請求失敗:', xhr.status);}}
};// 錯誤處理
xhr.onerror = function() {console.error('網絡錯誤');
};xhr.send();

特點

  • ? 兼容性極好(IE6+)

  • ? 回調地獄風險

  • ? 需手動處理JSON解析


二、Fetch API (現代標準)

基于Promise的標準化方案

fetch('https://api.example.com/data', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ key: 'value' })
})
.then(response => {if (!response.ok) throw new Error('HTTP錯誤:' + response.status);return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('請求失敗:', error));

優化技巧

  • 超時控制:

    const timeout = (ms) => new Promise((_, reject) => setTimeout(() => reject(new Error('請求超時')), ms)
    );Promise.race([fetch(url), timeout(5000)]).then(...);

特點

  • ? 原生Promise鏈式調用

  • ? 默認不攜帶Cookie(需配置credentials: 'include'

  • ? 部分舊瀏覽器需polyfill


三、Axios (主流第三方庫)

功能最全面的請求庫

import axios from 'axios';// 發起請求
axios.get('https://api.example.com/data', {params: { id: 123 },timeout: 5000
})
.then(response => console.log(response.data))
.catch(error => {if (error.response) {// 服務器響應異常(4xx/5xx)console.log(error.response.status);} else if (error.request) {// 請求已發出但無響應console.log('無響應:', error.request);} else {// 其他錯誤console.log('錯誤:', error.message);}
});// 全局配置
axios.defaults.baseURL = 'https://api.example.com';
axios.interceptors.request.use(config => {config.headers.Authorization = localStorage.getItem('token');return config;
});

核心優勢

  • ? 自動JSON轉換

  • ? 請求/響應攔截器

  • ? 并發控制:axios.all()

  • ? 取消請求:CancelToken


四、async/await (終極異步方案)

用同步寫法處理異步(需配合Fetch/Axios)

async function fetchData() {try {const response = await fetch('https://api.example.com/data');const data = await response.json();console.log(data);} catch (error) {console.error('請求失敗:', error);}
}// 并行請求
async function fetchMulti() {const [user, posts] = await Promise.all([fetch('/user'),fetch('/posts')]);
}

五、WebSocket (雙向實時通信)

非HTTP協議的持久化連接

const socket = new WebSocket('wss://api.example.com/ws');socket.onopen = () => {socket.send(JSON.stringify({ type: 'join' }));
};socket.onmessage = (event) => {console.log('收到消息:', event.data);
};socket.onclose = () => {console.log('連接關閉');
};

六、技術選型對比表

方案適用場景優點缺點
XMLHttpRequest兼容IE的低要求項目無需外部依賴代碼冗長、回調地獄
Fetch API現代瀏覽器項目原生支持、Promise化錯誤處理不夠直觀
Axios企業級復雜應用功能全面、攔截器機制需額外引入庫
WebSocket實時聊天、股票行情雙向實時通信需后端配合協議支持

七、最佳實踐建議

  1. 首選Axios:復雜項目用攔截器統一處理鑒權/錯誤

  2. SSR兼容:服務端渲染使用isomorphic-fetchaxios

  3. 性能優化

    • 請求去重:同一API短時間內只發一次

    • 緩存策略:Cache-Control?+ 本地緩存

  4. 安全防護

    • CSRF Token自動攜帶

    • 請求體簽名防篡改

掌握這些方法后,可根據項目需求靈活選擇最合適的異步通信方案!

js循環機制

JavaScript 的循環機制(事件循環)就像一家繁忙的餐廳,用三步就能理解它的工作原理:


一、餐廳廚房的比喻

角色對應 JavaScript 概念作用
廚師👨🍳主線程(JS 引擎)一次只能炒一個菜(單線程)
服務員💁♀?事件循環(Event Loop)協調誰先上菜(任務調度)
煮面鍋🍜異步任務(setTimeout、網絡請求等)需要等待的操作
出菜口📤任務隊列(Task Queue)存放煮好的面(完成的任務)

二、工作流程(三步走)

1. 先做馬上能出餐的菜(同步任務)
  • 場景:顧客點了一份炒飯(同步任務)和一碗需要煮的面(異步任務)

  • 操作

    console.log('開始炒飯'); // 同步任務,立即執行
    setTimeout(() => {      // 異步任務,交給"煮面鍋"console.log('面煮好了');
    }, 2000);
    console.log('繼續做其他菜'); // 繼續執行同步任務

  • 結果輸出

    開始炒飯
    繼續做其他菜
    (等待2秒...)
    面煮好了

2. 煮好的面要排隊(任務隊列)
  • 煮面過程

    • 廚師把鍋交給后廚(瀏覽器其他線程處理)

    • 繼續做其他菜(執行后續代碼)

    • 面煮好后,服務員把面放到出菜口(任務隊列)


3. 服務員按規則上菜(事件循環)
  • 規則

    1. VIP 訂單先處理(微任務隊列)
      比如:Promise?的回調(.then())、MutationObserver

      Promise.resolve().then(() => {console.log('VIP 面條加急處理!');
      });
    2. 普通訂單后處理(宏任務隊列)
      比如:setTimeoutsetInterval、用戶點擊事件

  • 完整流程

    1. 做完所有同步任務(炒飯)
    2. 立即處理所有 VIP 訂單(微任務)
    3. 如果有新 VIP 訂單,繼續處理直到清空
    4. 上一個宏任務結束,取一個普通訂單(如煮面回調)
    5. 重復這個循環...

三、真實代碼示例

console.log('開始點餐'); // 同步任務// 宏任務(普通訂單)
setTimeout(() => {console.log('您的面煮好了'); 
}, 0);// 微任務(VIP 訂單)
Promise.resolve().then(() => {console.log('VIP 小菜已贈送');
});console.log('繼續服務其他顧客'); // 同步任務

輸出順序

開始點餐 繼續服務其他顧客 VIP 小菜已贈送 您的面煮好了


四、為什么這樣設計?

  • 不卡頓:廚師(主線程)不會傻等煮面(異步任務),可以繼續干活

  • 高效:VIP 訂單(微任務)能插隊處理,保證高優先級任務快速響應

  • 有序:所有任務排隊處理,不會出現混亂


下次看到?Promise?和?setTimeout?時,想想這個餐廳模型就明白了! 🍔 → 🍜 → 💁♀? → 🔁


uniapp相關面試題

uniapp制作的app想上傳文件pdf如何實現?

一、完整實現流程

  1. 選擇文件?→ 2.?校驗文件?→ 3.?顯示預覽?→ 4.?上傳服務器?→ 5.?處理結果

二、核心代碼實現(全平臺兼容版)

<template><view class="container"><!-- 上傳按鈕 --><button @click="selectPDF" type="primary">選擇PDF文件</button><!-- 文件信息展示 --><view v-if="fileInfo" class="file-info"><text>文件名:{{ fileInfo.name }}</text><text>大小:{{ (fileInfo.size / 1024 / 1024).toFixed(2) }}MB</text><button @click="startUpload" type="primary">開始上傳</button></view><!-- 進度條 --><progress v-if="progress > 0" :percent="progress" show-info /></view>
</template><script>
export default {data() {return {fileInfo: null,  // 文件信息progress: 0,     // 上傳進度uploadTask: null // 上傳任務對象(用于取消上傳)}},methods: {// 1. 選擇PDF文件async selectPDF() {try {const res = await uni.chooseFile({count: 1,type: 'file',extension: ['pdf'],sourceType: ['album', 'camera'] // 相冊或文件系統})// 獲取文件信息this.fileInfo = {path: res.tempFiles[0].path,name: res.tempFiles[0].name,size: res.tempFiles[0].size}// 預覽文件(僅App可用)if (uni.getSystemInfoSync().platform === 'android' || uni.getSystemInfoSync().platform === 'ios') {uni.openDocument({filePath: this.fileInfo.path,fileType: 'pdf'})}} catch (err) {uni.showToast({ title: '選擇文件失敗', icon: 'none' })}},// 2. 上傳文件async startUpload() {if (!this.fileInfo) return// 校驗文件大小(示例限制20MB)if (this.fileInfo.size > 20 * 1024 * 1024) {uni.showToast({ title: '文件不能超過20MB', icon: 'none' })return}this.progress = 0try {this.uploadTask = uni.uploadFile({url: 'https://your-api.com/upload',filePath: this.fileInfo.path,name: 'file',formData: {userId: '123',timestamp: Date.now()},success: (res) => {if (res.statusCode === 200) {const data = JSON.parse(res.data)uni.showToast({ title: '上傳成功', icon: 'success' })console.log('服務器返回:', data)} else {uni.showToast({ title: `上傳失敗:${res.errMsg}`, icon: 'none' })}},fail: (err) => {console.error('上傳失敗:', err)uni.showToast({ title: '上傳失敗', icon: 'none' })},complete: () => {this.uploadTask = null}})// 監聽進度this.uploadTask.onProgressUpdate((res) => {this.progress = res.progress})} catch (err) {uni.showToast({ title: '上傳異常', icon: 'none' })}},// 3. 取消上傳cancelUpload() {if (this.uploadTask) {this.uploadTask.abort()uni.showToast({ title: '已取消上傳', icon: 'none' })}}}
}
</script><style>
.container {padding: 20px;
}
.file-info {margin-top: 20px;padding: 15px;background-color: #f5f5f5;border-radius: 5px;
}
</style>
 

三、關鍵配置說明

1. 平臺適配要點
平臺配置項
Android需在manifest.json中添加權限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
iOS需在manifest.json中配置:
"ios" : { "permission" : { "NSPhotoLibraryUsageDescription" : "需要訪問相冊選擇文件" } }
所有平臺使用uni.chooseFile統一接口,無需處理平臺差異
2. 文件選擇參數優化
// 更嚴格的文件類型校驗
const isPDF = file.type === 'application/pdf' || file.name.endsWith('.pdf') || /\.pdf$/i.test(file.name)// 獲取文件真實路徑(App專用)
if (plus.io) {file.realPath = plus.io.convertLocalFileSystemURL(file.path)
}

四、服務器端示例(Node.js + Express)

const express = require('express')
const multer = require('multer')
const path = require('path')
const app = express()// 配置文件存儲
const storage = multer.diskStorage({destination: (req, file, cb) => {cb(null, path.join(__dirname, 'uploads'))},filename: (req, file, cb) => {cb(null, `${Date.now()}-${file.originalname}`)}
})// 文件過濾
const fileFilter = (req, file, cb) => {if (file.mimetype === 'application/pdf') {cb(null, true)} else {cb(new Error('只允許上傳PDF文件'), false)}
}const upload = multer({ storage,fileFilter,limits: { fileSize: 20 * 1024 * 1024 } // 限制20MB
})// 上傳接口
app.post('/upload', upload.single('file'), (req, res) => {console.log('接收到文件:', req.file)console.log('附加參數:', req.body)res.json({code: 200,message: '上傳成功',data: {filename: req.file.filename,originalname: req.file.originalname,size: req.file.size,downloadUrl: `/download/${req.file.filename}`}})
})// 啟動服務
app.listen(3000, () => {console.log('服務器運行在 http://localhost:3000')
})

五、增強功能實現

1. 斷點續傳(App端)
// 獲取文件分片
const fileManager = plus.io.getFileSystemManager()
fileManager.readFile({filePath: file.path,position: 0,length: chunkSize,success: (res) => {const chunk = res.data// 上傳分片邏輯...}
})
2. 文件加密上傳
// 使用crypto-js加密
import CryptoJS from 'crypto-js'const encryptFile = (file) => {const wordArray = CryptoJS.lib.WordArray.create(file)return CryptoJS.AES.encrypt(wordArray, 'secret-key').toString()
}
3. 七牛云/OSS直傳
// 獲取服務端簽名后直傳
uni.request({url: 'https://your-api.com/get-oss-token',success: (res) => {const ossConfig = res.datauni.uploadFile({url: ossConfig.host,filePath: this.fileInfo.path,name: 'file',formData: {key: ossConfig.key,policy: ossConfig.policy,OSSAccessKeyId: ossConfig.accessid,signature: ossConfig.signature}})}
})
 

六、常見問題解決方案

1.?Android文件路徑問題
// 轉換真實路徑
if (this.fileInfo.path.startsWith('file://')) {this.fileInfo.path = this.fileInfo.path.replace('file://', '')
}
2.?iOS無法選擇文件

檢查manifest.json是否正確配置:

"ios" : {"permission" : {"NSPhotoLibraryUsageDescription" : "需要訪問相冊選擇文件","NSPhotoLibraryAddUsageDescription" : "需要保存文件到相冊"}
}
3.?大文件上傳失敗
  • 分片上傳(每5MB一個分片)

  • 顯示進度和暫停/繼續功能

  • 后臺服務需支持分片合并

七、性能優化建議

  1. 前端壓縮:使用pdf-lib等庫壓縮PDF

  2. 緩存機制:已上傳文件記錄MD5避免重復上傳

  3. 隊列控制:多個文件時限制并發上傳數

uni-app實現掃碼的幾種方式

1、官方掃碼接口

優點:uni.scanCode(OBJECT)就可以直接調用,方便快捷,支持安卓、ios,如果制作小程序,便可以直接轉換成微信等官方掃碼api。
缺點:安卓、ios端識別率非常差,并且掃碼耗時很長,很多條件下,無法識別二維碼。

2、支付寶掃碼插件

直接在插件市場就可以下載使用
優點:免費,并且識別率非常高
缺點:需要配置阿里云控制臺,而且阿里在控制臺有初始埋點,第一次使用如果沒有關閉,會直接短信通知欠費,不能離線掃碼,數據安全性不詳。

3、華為掃碼插件

直接在插件市場就可以下載使用
優點:識別率不錯,可以離線掃碼
缺點:需要付費88元,我在測試階段掃碼掃出空字符,導致數據傳值失敗,需要在掃碼獲取的值做一些處理,下面附上處理 方式。

this.invoicedata = ret.sValue.replace(/[\xa0\x00-\x09\x0b\x0c\x0e-\x1f\x7f]/g, '');

4、微信掃碼

優點:免費,識別率高
缺點:目前只支持小程序,沒有開放接口。

這道答案來源于uni-app實現掃碼的幾種方式_uniapp scancode-CSDN博客


CSS相關面試題

PC網頁轉h5如何響應式布局?

在將 PC 網頁轉換為 H5 響應式布局時,需遵循移動優先原則并兼顧多端適配。以下是完整實現方案:


一、核心布局策略

<!-- 基礎視口配置 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><!-- 移動端專用 meta -->
<meta name="format-detection" content="telephone=no">
<meta name="apple-mobile-web-app-capable" content="yes">
1.?彈性容器布局
.container {width: 100%;max-width: 1200px;  /* PC端最大寬度限制 */margin: 0 auto;padding: 0 15px;    /* 移動端安全邊距 */display: flex;flex-wrap: wrap;    /* 允許換行適應小屏 */
}
2.?網格系統實現
/* 12列響應式網格 */
.col {flex: 0 0 100%;     /* 移動端默認占滿寬度 */padding: 10px;
}@media (min-width: 768px) {.col-md-6 {flex: 0 0 50%;    /* 平板分兩列 */}
}@media (min-width: 992px) {.col-lg-3 {flex: 0 0 25%;    /* PC端分四列 */}
}

二、元素級適配方案

1.?字體響應式
:root {font-size: 14px;    /* 基準字號 */
}@media (min-width: 768px) {:root {font-size: 16px;  /* 中屏增大字號 */}
}h1 {font-size: 2rem;    /* 28px -> 32px */line-height: 1.3;
}
2.?圖片適配
<picture><!-- 移動端優先加載小圖 --><source media="(max-width: 767px)" srcset="mobile.jpg"><!-- 平板 --><source media="(max-width: 991px)" srcset="tablet.jpg"><!-- PC端 --><img src="desktop.jpg" alt="示例" style="width:100%; height:auto;">
</picture>
3.?表格優化
.table-wrapper {overflow-x: auto;  /* 橫向滾動 */-webkit-overflow-scrolling: touch;
}table {min-width: 600px;  /* 保持表格最小可讀寬度 */
}

三、交互適配技巧

1.?導航欄改造
<!-- 移動端漢堡菜單 -->
<button class="menu-toggle">?</button>
<nav class="main-nav"><a href="#">首頁</a><a href="#">產品</a>
</nav><style>
.menu-toggle {display: none; /* PC端隱藏 */
}@media (max-width: 767px) {.menu-toggle {display: block; /* 移動端顯示 */}.main-nav {display: none;position: fixed;top: 0;left: 0;width: 100%;background: white;}.main-nav.active {display: block;}
}
</style>
2.?表單優化
input[type="text"],
input[type="email"] {width: 100%;height: 40px;padding: 8px;font-size: 16px;  /* 避免移動端縮放 */border: 1px solid #ddd;
}

四、性能優化專項

1.?資源按需加載
<!-- 移動端不加載大圖 -->
<div class="hero-image" data-src="desktop-bg.jpg" data-mobile-src="mobile-bg.jpg"></div><script>
function loadAdaptiveImage() {const images = document.querySelectorAll('[data-mobile-src]');images.forEach(img => {const src = window.innerWidth < 768 ? img.dataset.mobileSrc : img.dataset.src;img.style.backgroundImage = `url(${src})`;});
}
window.addEventListener('resize', loadAdaptiveImage);
</script>
2.?觸控反饋優化
.button {min-width: 44px;   /* 最小點擊區域 */min-height: 44px;padding: 12px 24px;transition: opacity 0.3s;
}.button:active {opacity: 0.7;      /* 按壓反饋 */
}

五、多端調試方案

1.?Chrome 設備模擬
  • 打開 DevTools → Device Toolbar

  • 測試不同DPR(Device Pixel Ratio)

2.?真機調試
# 本地服務綁定IP
npm run dev -- --host 0.0.0.0# 手機訪問電腦IP:端口
3.?自動化測試工具
// 使用Puppeteer多分辨率截圖
const puppeteer = require('puppeteer');async function testResponsive() {const browser = await puppeteer.launch();const page = await browser.newPage();const devices = [{name: 'mobile', width: 375, height: 667},{name: 'tablet', width: 768, height: 1024},{name: 'desktop', width: 1200, height: 800}];for (let device of devices) {await page.setViewport(device);await page.goto('http://localhost:3000');await page.screenshot({path: `screenshot-${device.name}.png`});}await browser.close();
}
testResponsive();

六、常見問題解決

  • 1px邊框問題

.border {position: relative;
}
.border::after {content: '';position: absolute;left: 0;bottom: 0;width: 100%;height: 1px;background: #ddd;transform: scaleY(0.5);
}
  • fixed定位抖動

.header {position: fixed;top: 0;width: 100%;/* 開啟GPU加速 */transform: translateZ(0);backface-visibility: hidden;
}

通過以上方案,可實現從PC到H5的高質量響應式適配,兼顧視覺效果與交互體驗。核心原則是:彈性布局打底 + 媒體查詢微調 + 移動優先交互

css想做動畫有哪些方法?

在 CSS 中實現動畫主要有以下幾種核心方法,每種方法都有其適用場景和特性:


一、基礎動畫方法

1.?Transition(過渡動畫)
  • 用途:元素屬性變化時的平滑過渡(如 hover 效果)

  • 代碼示例

    .box {width: 100px;transition: width 0.3s ease-in-out;
    }
    .box:hover {width: 200px;
    }
  • 特點

    • 只能定義開始和結束狀態

    • 支持屬性:transformopacitycolor?等可過渡屬性

    • 性能優化:優先使用?transform?和?opacity(觸發 GPU 加速)

2.?Keyframes Animation(關鍵幀動畫)
  • 用途:復雜多階段動畫(如旋轉、閃爍)

  • 代碼示例

    @keyframes rotate {0% { transform: rotate(0deg); }100% { transform: rotate(360deg); }
    }.spinner {animation: rotate 2s linear infinite;
    }
  • 核心屬性

    animation: name duration timing-function delay iteration-count direction fill-mode;
  • 高級技巧

    • 使用?steps()?函數實現逐幀動畫:

      @keyframes walk {from { background-position: 0 0; }to { background-position: -1600px 0; }
      }
      .character {animation: walk 1s steps(8) infinite;
      }

二、性能優化技巧

1.?硬件加速
.animate {transform: translateZ(0); /* 或 will-change: transform; */
}
2.?限制重繪區域
.container {contain: strict; /* 限制瀏覽器重繪范圍 */
}
3.?避免布局抖動
  • 優先使用?transform?替代?top/left?位移

  • 使用?requestAnimationFrame?同步動畫(JS 輔助)


三、進階動畫方案

1.?CSS 變量驅動動畫
:root {--rotate: 0deg;
}.box {transform: rotate(var(--rotate));transition: transform 0.3s;
}/* JS 控制動畫 */
box.style.setProperty('--rotate', '45deg');
2.?SVG 動畫
<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40"><animate attributeName="r" from="40" to="20" dur="1s" repeatCount="indefinite"/></circle>
</svg>
3.?動畫庫擴展
  • Animate.css(預設動畫庫):

    <div class="animate__animated animate__bounce"></div>
  • Motion One(現代輕量庫):

    import { animate } from "motion";
    animate(".box", { x: 100 }, { duration: 0.3 });

四、方案對比表

方法適用場景優點缺點
Transition簡單狀態過渡簡單高效、性能好無法控制中間狀態
Keyframes復雜多階段動畫完全控制動畫流程代碼量較大
CSS 變量動態控制動畫參數靈活、易于JS交互兼容性要求 IE11+
SVG 動畫矢量圖形動畫分辨率無關、路徑動畫學習成本較高
動畫庫快速實現復雜效果開箱即用、效果豐富增加項目體積

五、調試工具

  1. Chrome DevTools 動畫面板

    • 查看動畫時間軸

    • 修改動畫參數實時預覽

  2. 性能監測

    • 使用 Performance 面板分析幀率

    • 檢查 Layout/Paint 耗時


六、最佳實踐建議

  1. 優先使用 CSS 原生動畫(而非 JS 動畫)

  2. 限制同時運行的動畫數量(一般不超過 5 個)

  3. 移動端優化

    • 動畫時長建議 200-500ms

    • 使用?@media (prefers-reduced-motion)?適配無障礙

    @media (prefers-reduced-motion: reduce) {* { animation: none !important; }
    }

掌握這些方法后,可根據具體需求選擇最合適的動畫實現方案!🎉

其他綜合問題

如何不讓網頁上的水印被去除?

在PC端頁面實現防篡改水印需要綜合多種技術手段,以下是一套較為全面的解決方案:

一、動態Canvas水印方案

function createDynamicWatermark(text) {const canvas = document.createElement('canvas');const ctx = canvas.getContext('2d');canvas.width = 300;canvas.height = 200;// 繪制基礎水印ctx.font = '14px Arial';ctx.fillStyle = 'rgba(200,200,200,0.2)';ctx.rotate(-20 * Math.PI / 180);ctx.fillText(text, 10, 100);// 添加防偽波紋for(let i=0;i<canvas.width;i+=30){ctx.beginPath();ctx.moveTo(i, 0);ctx.lineTo(i, canvas.height);ctx.strokeStyle = 'rgba(0,0,0,0.02)';ctx.stroke();}// 生成動態背景圖const dataUrl = canvas.toDataURL();const watermarkDiv = document.createElement('div');watermarkDiv.style.cssText = `position: fixed;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none;z-index: 999999;background: url(${dataUrl}) left top repeat;mix-blend-mode: multiply;`;// 防刪除保護watermarkDiv.setAttribute('id', 'secure-watermark');Object.defineProperty(watermarkDiv, 'id', {configurable: false,writable: false});document.body.appendChild(watermarkDiv);
}

二、防篡改保護機制

DOM變動監控

const observer = new MutationObserver(mutations => {mutations.forEach(mutation => {Array.from(mutation.removedNodes).forEach(node => {if (node.id === 'secure-watermark') {document.body.appendChild(node);}});});
});observer.observe(document.body, {childList: true,subtree: true
});

樣式篡改防御

const styleGuard = setInterval(() => {const watermark = document.getElementById('secure-watermark');if (!watermark) {createDynamicWatermark();return;}const styles = window.getComputedStyle(watermark);const protectedProps = {'display': 'block','opacity': '1','visibility': 'visible'};Object.entries(protectedProps).forEach(([prop, value]) => {if (styles[prop] !== value) {watermark.style[prop] = value;}});
}, 1000);

三、用戶行為監控

window.addEventListener('keydown', (e) => {// 屏蔽開發者工具快捷鍵const devtoolKeys = [e.ctrlKey && e.keyCode === 85, // Ctrl+Ue.ctrlKey && e.shiftKey && e.keyCode === 73, // Ctrl+Shift+Ie.keyCode === 123 // F12];if (devtoolKeys.some(Boolean)) {e.preventDefault();alert('安全警告:禁止開發者工具操作!');window.location.reload();}
});// 防止右鍵檢查
document.addEventListener('contextmenu', (e) => {e.preventDefault();return false;
});// 防截圖干擾
const noiseCanvas = document.createElement('canvas');
noiseCanvas.style.cssText = `position: fixed;top:0;left:0;pointer-events: none;z-index: 9999999;
`;
document.body.appendChild(noiseCanvas);function generateNoise() {const ctx = noiseCanvas.getContext('2d');const imageData = ctx.createImageData(noiseCanvas.width, noiseCanvas.height);const data = imageData.data;for(let i=0;i<data.length;i+=4){const val = Math.random()*255;data[i] = data[i+1] = data[i+2] = val;data[i+3] = 5; }ctx.putImageData(imageData, 0, 0);requestAnimationFrame(generateNoise);
}noiseCanvas.width = window.innerWidth;
noiseCanvas.height = window.innerHeight;
generateNoise();

四、服務端配合方案

  • 動態水印信息

// 每次請求攜帶動態token
async function getWatermarkText() {const res = await fetch('/api/watermark-token');const { token } = await res.json();return `機密 ${token} ${Date.now()}`;
}// 定期更新水印
setInterval(async () => {const newText = await getWatermarkText();updateWatermark(newText);
}, 300000);
  • 內容加密驗證

// 使用CryptoJS進行內容簽名
const contentHash = CryptoJS.HmacSHA256(document.body.innerText, 'secretKey'
).toString();// 后臺校驗示例
app.post('/verify-content', (req, res) => {const clientHash = req.body.hash;const serverHash = CryptoJS.HmacSHA256(req.body.content,'secretKey').toString();if(clientHash !== serverHash) {// 觸發內容篡改警報sendAlert('檢測到內容篡改!');}
});

五、防御等級說明

防御層級技術手段防御能力
初級防御基礎CSS水印★☆☆☆☆
中級防御Canvas動態水印+DOM監控★★★☆☆
高級防御行為監控+服務端驗證★★★★☆
終極防御硬件級DRM方案★★★★★

注意事項:

  1. 定期更新水印算法(建議每月迭代)

  2. 結合業務日志記錄用戶操作行為

  3. 重要數據建議使用PDF等不可逆格式展示

  4. 法律層面增加水印聲明條款

任何前端方案都無法做到絕對防篡改,建議根據業務安全等級選擇適當方案,關鍵數據應結合后端驗證和權限控制。

HTTP和HTTPS的區別

HTTP(超文本傳輸協議)和 HTTPS(安全超文本傳輸協議)的核心區別在于數據傳輸的安全性,以下是兩者的詳細對比:


一、核心區別總結

特性HTTPHTTPS
安全性明文傳輸,數據可被竊聽/篡改加密傳輸,防竊聽/防篡改
協議應用層協議HTTP + SSL/TLS 安全層
默認端口80443
證書無需證書需CA機構頒發的SSL證書
性能無加密開銷,速度稍快有加密計算開銷,但現代硬件影響可忽略
SEO搜索引擎可能降權搜索引擎優先收錄(如Google明確支持)

二、技術實現差異

1.?加密機制(核心)
  • HTTP
    數據以明文形式傳輸,可直接被中間人讀取:

    GET /login HTTP/1.1
    Host: example.com
    username=admin&password=123456  ← 明文傳輸!
  • HTTPS
    通過SSL/TLS協議加密數據,傳輸內容為密文:

    ���]�k�M�I�4��Q�V��x�d� ← 加密后的亂碼數據
2.?SSL/TLS工作流程
  1. 握手階段(非對稱加密):

    • 客戶端驗證服務器證書有效性

    • 協商加密算法(如RSA、ECDHE)

    • 生成會話密鑰(Session Key)

  2. 數據傳輸(對稱加密):

    • 使用會話密鑰加密通信內容


三、HTTPS核心優勢

1.?防竊聽(Encryption)
  • 所有數據加密傳輸,即使被截獲也無法解密

  • 示例:公共WiFi下登錄賬號時,HTTPS可防止密碼泄露

2.?防篡改(Integrity)
  • 使用MAC(消息認證碼)驗證數據完整性

  • 示例:阻止運營商插入廣告代碼

3.?身份認證(Authentication)
  • SSL證書驗證網站真實身份,防止釣魚網站

  • 示例:瀏覽器地址欄顯示鎖標志和公司名稱


四、部署HTTPS的要求

1.?SSL證書類型
證書類型驗證等級適用場景
DV(域名驗證)驗證域名所有權個人博客、小型網站
OV(組織驗證)驗證企業/組織身份企業官網
EV(擴展驗證)嚴格身份驗證(地址欄綠標)銀行、電商等敏感領域
2.?部署步驟
  1. 購買或申請免費證書(如Let's Encrypt)

  2. 在服務器安裝證書(Nginx示例):

    server {listen 443 ssl;ssl_certificate /path/to/cert.pem;ssl_certificate_key /path/to/private.key;
    }
  3. 強制HTTP跳轉HTTPS:

    server {listen 80;return 301 https://$host$request_uri;
    }

五、性能優化技巧

  1. 會話復用(Session Resumption)
    減少SSL握手次數,降低延遲:

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

  2. 啟用HTTP/2
    HTTPS下可啟用HTTP/2協議提升性能:

    listen 443 ssl http2;

六、常見誤解澄清

  • 誤區1:"HTTPS會顯著拖慢網站速度"
    → 現代服務器性能下,TLS握手開銷僅增加約1 RTT(經優化可降至0 RTT)

  • 誤區2:"只有支付頁面需要HTTPS"
    → 現代Web標準(如PWA、Geolocation API)要求全站HTTPS

  • 誤區3:"HTTPS無法被劫持"
    → 若客戶端安裝偽證書(如企業監控),仍可能被中間人攻擊


七、如何驗證HTTPS安全性

  1. 瀏覽器地址欄顯示鎖形圖標

  2. 通過SSL Labs測試檢查配置:

    Rating: A+ (最佳評級)

總結:HTTPS通過加密和身份驗證構建安全傳輸通道,是現代Web應用的必備基礎,所有新建網站都應默認啟用HTTPS

前端瀏覽器安全如何注意?

為了保障前端瀏覽器的安全性,需要從代碼防護、數據傳輸、用戶輸入處理等多方面入手。以下是系統化的安全防護方案及具體實施方法:


一、基礎防護體系

1. 啟用HTTPS強制加密
# Nginx配置(強制跳轉HTTPS)
server {listen 80;server_name example.com;return 301 https://$host$request_uri;
}

附加措施

  • 使用HSTS頭(強制瀏覽器使用HTTPS)

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
2. 安全頭配置
# 安全響應頭示例
add_header X-Frame-Options "SAMEORIGIN";               # 防點擊劫持
add_header X-Content-Type-Options "nosniff";          # 禁止MIME嗅探
add_header Referrer-Policy "strict-origin-when-cross-origin"; # 控制Referer泄露
add_header Permissions-Policy "geolocation=()";       # 禁用不必要權限

二、攻擊防御專項

1. XSS(跨站腳本攻擊)防御
  • 輸入過濾

    // 使用DOMPurify過濾HTML
    import DOMPurify from 'dompurify';
    const cleanHTML = DOMPurify.sanitize(userInput);
  • 輸出轉義

    <!-- Vue自動轉義 -->
    <div>{{ userContent }}</div><!-- 手動轉義 -->
    <div v-html="safeHTML"></div>
  • CSP策略

    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'">
2. CSRF(跨站請求偽造)防御
  • Token驗證

    // 后端生成Token
    const csrfToken = crypto.randomBytes(32).toString('hex');
    res.cookie('XSRF-TOKEN', csrfToken);// 前端發送請求攜帶Token
    axios.defaults.headers.common['X-XSRF-TOKEN'] = getCookie('XSRF-TOKEN');
  • SameSite Cookie

    // 設置Cookie屬性
    res.cookie('sessionID', '123', { sameSite: 'Strict', secure: true 
    });
3. 點擊劫持防御
add_header X-Frame-Options "DENY";  # 完全禁止嵌入
# 或
add_header Content-Security-Policy "frame-ancestors 'self'"; 

三、數據安全防護

1. 敏感數據處理
  • 前端加密

    // 使用Web Crypto API加密
    const encryptedData = await crypto.subtle.encrypt({ name: 'AES-GCM', iv },key,new TextEncoder().encode(data)
    );
  • 安全存儲

    // 避免localStorage存儲敏感信息
    sessionStorage.setItem('tempData', encryptedData);
2. 第三方資源校驗
<!-- 使用SRI校驗CDN資源 -->
<script src="https://cdn.example.com/jquery.js" integrity="sha384-...">
</script>

四、用戶輸入與認證

1. 輸入驗證
// 郵箱格式校驗
const isValidEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);// 防止SQL注入
const sanitizeInput = (input) => input.replace(/['"\\;]/g, '');
2. 認證安全
  • 密碼策略

    // 前端密碼強度校驗
    const isStrongPassword = (pwd) => pwd.length >= 8 && /[A-Z]/.test(pwd) && /[0-9]/.test(pwd);
  • 雙因素認證

    // 集成Google Authenticator
    import { authenticator } from 'otplib';
    const secret = authenticator.generateSecret();
    const token = authenticator.generate(secret);

五、持續監控與更新

1. 依賴安全掃描
# 使用npm audit檢查漏洞
npm audit# 使用Snyk深度檢測
npx snyk test
2. 實時監控
  • 錯誤追蹤:接入Sentry監控XSS等異常

  • 入侵檢測:部署WAF(Web應用防火墻)


六、安全等級對照表

安全等級適用場景防護措施
基礎級小型展示網站HTTPS + CSP + XSS過濾
標準級企業級應用基礎級 + CSRF Token + 輸入驗證 + 安全頭
高級級金融/政務系統標準級 + 雙因素認證 + 實時監控 + 前端加密 + 人工滲透測試

七、應急響應方案

  1. 漏洞響應流程

    • 發現漏洞 → 評估影響 → 熱修復 → 通知用戶

  2. 數據泄露處理

    • 立即重置相關憑證

    • 啟用日志審計追溯攻擊路徑

    • 根據法律要求通知受影響用戶


通過以上綜合措施,可構建多層次的前端安全防護體系。關鍵點在于:默認安全原則 + 縱深防御 + 持續監控,同時需結合具體業務場景調整防護策略。


PC端開發大文件如何上傳?卡住了怎么辦?失敗了后如何繼續上傳?

在前端PC端實現大文件上傳并處理中斷和續傳的問題,可以采用分塊上傳與斷點續傳的策略。以下是詳細的解決方案:


1. 分塊上傳(Chunked Upload)

將大文件分割為多個小塊(如1MB/塊),分別上傳,降低單次請求壓力,便于失敗后重試。

實現步驟:
  1. 前端分塊處理:

    const CHUNK_SIZE = 1 * 1024 * 1024; // 1MB
    const file = document.getElementById('file-input').files[0];
    const chunks = [];
    let start = 0;while (start < file.size) {const chunk = file.slice(start, start + CHUNK_SIZE);chunks.push(chunk);start += CHUNK_SIZE;
    }
  2. 生成文件唯一標識:
    使用文件內容的哈希(如SHA-256)作為唯一標識,避免同名文件沖突。

    async function computeFileHash(file) {const buffer = await file.arrayBuffer();const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('');
    }
  3. 上傳單個塊:

    async function uploadChunk(chunk, chunkIndex, fileHash) {const formData = new FormData();formData.append('chunk', chunk);formData.append('chunkIndex', chunkIndex);formData.append('fileHash', fileHash);formData.append('totalChunks', totalChunks);await fetch('/upload-chunk', {method: 'POST',body: formData,});
    }

2. 斷點續傳(Resumable Upload)

記錄已上傳的塊,失敗后僅上傳缺失部分。

實現步驟:
  1. 查詢服務器已上傳的塊:

    async function getUploadedChunks(fileHash) {const response = await fetch(`/uploaded-chunks?fileHash=${fileHash}`);return await response.json(); // 返回已上傳的塊索引數組,如[0,1,2]
    }
  2. 過濾未上傳的塊并繼續上傳:

    const uploadedChunks = await getUploadedChunks(fileHash);
    const chunksToUpload = chunks.filter((_, index) => !uploadedChunks.includes(index));// 控制并發上傳(如最多5個并行)
    const MAX_CONCURRENT = 5;
    const queue = chunksToUpload.map((chunk, index) => () => uploadChunk(chunk, index, fileHash));// 使用p-limit庫控制并發
    import pLimit from 'p-limit';
    const limit = pLimit(MAX_CONCURRENT);
    await Promise.all(queue.map(task => limit(task)));

3. 失敗處理與重試

  • 網絡錯誤重試:?為每個塊的上傳添加重試機制。

    async function uploadWithRetry(chunk, chunkIndex, fileHash, retries = 3) {try {await uploadChunk(chunk, chunkIndex, fileHash);} catch (error) {if (retries > 0) {await uploadWithRetry(chunk, chunkIndex, fileHash, retries - 1);} else {throw error;}}
    }

  • 服務端錯誤處理:?返回明確的錯誤狀態碼,前端根據狀態碼決定重試或報錯。


4. 服務器端實現

關鍵接口:
  1. 上傳塊接口(/upload-chunk):

    • 接收塊文件、塊索引、文件哈希。

    • 將塊保存到臨時目錄(按文件哈希組織)。

  2. 查詢已上傳塊接口(/uploaded-chunks):

    • 根據文件哈希返回已上傳的塊索引列表。

  3. 合并文件接口(/merge-file):

    • 所有塊上傳完成后,按順序合并成完整文件。

示例偽代碼(Node.js):
// 保存塊
app.post('/upload-chunk', (req, res) => {const { chunk, chunkIndex, fileHash } = req.body;const chunkDir = `./temp/${fileHash}`;fs.mkdirSync(chunkDir, { recursive: true });fs.writeFileSync(`${chunkDir}/${chunkIndex}`, chunk.buffer);res.status(200).send('Chunk uploaded');
});// 合并文件
app.post('/merge-file', (req, res) => {const { fileHash, fileName } = req.body;const chunkDir = `./temp/${fileHash}`;const chunks = fs.readdirSync(chunkDir).sort((a, b) => a - b);const filePath = `./uploads/${fileName}`;chunks.forEach(chunk => {fs.appendFileSync(filePath, fs.readFileSync(`${chunkDir}/${chunk}`));});fs.rmdirSync(chunkDir, { recursive: true }); // 清理臨時文件res.status(200).send('File merged');
});

5. 用戶體驗優化

  • 進度顯示:?監聽每個塊的上傳進度,計算總進度。

    let uploadedSize = 0;
    chunks.forEach((chunk, index) => {uploadChunk(chunk, index).then(() => {uploadedSize += chunk.size;const progress = (uploadedSize / file.size) * 100;updateProgressBar(progress);});
    });
  • 暫停/恢復:?使用AbortController取消請求,保存已上傳狀態。

    const controllers = new Map();function uploadChunk(chunk, index) {const controller = new AbortController();controllers.set(index, controller);return fetch(url, {signal: controller.signal,// ...});
    }// 暫停上傳
    function pauseUpload() {controllers.forEach(controller => controller.abort());
    }

6. 注意事項

  • 文件一致性校驗:?合并后對比服務器端文件的哈希與前端計算的哈希。

  • 清理臨時文件:?設置定時任務清理未完成的過期上傳。

  • 分塊大小調整:?根據網絡情況動態調整塊大小(如1MB-5MB)。

通過上述方案,可有效解決大文件上傳中的中斷、續傳和失敗重試問題,提升用戶體驗。


如何記錄接口報錯并且展示?

在前端中記錄接口報錯并展示錯誤信息,是提升用戶體驗和排查問題的重要手段。以下是分步驟的實現方案:


一、錯誤捕獲與記錄

1. 使用請求攔截器(以 Axios 為例)
// 創建 axios 實例
const instance = axios.create();// 響應攔截器
instance.interceptors.response.use((response) => response,(error) => {const { config, response } = error;const errorInfo = {time: new Date(),url: config?.url,method: config?.method,status: response?.status,message: response?.data?.message || error.message,};// 記錄錯誤(可擴展為上報服務器)logError(errorInfo);// 展示錯誤(可選,部分錯誤可能不需要立即展示)showErrorUI(errorInfo);return Promise.reject(error);}
);
2. 錯誤日志記錄方式
  • 本地存儲(臨時記錄)

    function logError(error) {const MAX_LOG_SIZE = 50;const logs = JSON.parse(localStorage.getItem('api_errors') || []);logs.push(error);if (logs.length > MAX_LOG_SIZE) logs.shift();localStorage.setItem('api_errors', JSON.stringify(logs));
    }
  • 上報到服務器(推薦生產環境使用)

    function reportErrorToServer(error) {navigator.sendBeacon('/api/logs', JSON.stringify(error));
    }

二、錯誤展示策略

1. 通用錯誤提示組件(React 示例)
import { Toast } from 'antd-mobile';function showErrorUI(error) {let message = '請求失敗,請稍后重試';// 根據錯誤類型定制提示if (error.status === 401) {message = '登錄已過期,請重新登錄';redirectToLogin();} else if (error.status >= 500) {message = '服務器開小差了,請聯系管理員';}Toast.show({content: message,duration: 3000,icon: 'fail',});
}
2. 專用錯誤信息面板
function ErrorPanel() {const [errors, setErrors] = useState([]);useEffect(() => {const errors = JSON.parse(localStorage.getItem('api_errors')) || [];setErrors(errors);}, []);return (<div className="error-panel"><h3>最近接口錯誤 ({errors.length})</h3>{errors.map((err, i) => (<div key={i} className="error-item"><p>[{err.time}] {err.method} {err.url}</p><p>狀態碼: {err.status} | 信息: {err.message}</p></div>))}</div>);
}

三、高級優化方案

  1. 錯誤分類處理

    function handleErrorByType(error) {if (!navigator.onLine) {showNetworkError();} else if (error.code === 'ECONNABORTED') {showTimeoutError();} else {showGenericError();}
    }
  2. 錯誤頻率限制

    let lastToastTime = 0;
    function showError(message) {if (Date.now() - lastToastTime > 5000) {Toast.show(message);lastToastTime = Date.now();}
    }
  3. 敏感信息過濾

    function sanitizeError(error) {const sanitized = { ...error };delete sanitized.headers.Authorization;delete sanitized.request.body.password;return sanitized;
    }

四、技術棧擴展建議

  • 錯誤監控平臺集成

    • 使用 Sentry/Bugsnag 進行專業錯誤監控

    import * as Sentry from '@sentry/browser';
    Sentry.init({ dsn: 'your_dsn' });function logError(error) {Sentry.captureException(new Error(error.message), {extra: error.context});
    }
  • 性能監控結合

    const startTime = Date.now();
    axios.get('/api/data').then(() => {logApiPerformance(Date.now() - startTime);});

五、注意事項

  1. 生產環境應避免顯示原始錯誤堆棧

  2. 401 錯誤需要特殊處理(清除登錄態)

  3. 重要接口可加入自動重試機制

    function retryRequest(config, retries = 3) {return axios(config).catch(err => {return retries > 0 ? retryRequest(config, retries - 1): Promise.reject(err);});
    }

通過以上方案,可以實現完整的接口錯誤處理流程,平衡用戶體驗與開發調試需求。建議根據具體業務場景選擇適合的優化點進行擴展。
?

前端輸入url后瀏覽器會先做什么?

以下是前端輸入 URL 后瀏覽器的主要處理流程,按順序分階段說明:


一、URL 解析階段(URL Parsing

  1. 協議補全
    自動補全協議頭(如輸入?google.com?→ 補全為?https://google.com

  2. 格式校驗
    檢查 URL 合法性(如特殊字符轉換?空格→%20


二、緩存檢查階段(Cache Check

緩存類型檢查順序典型場景
Service Worker最先檢查PWA 離線緩存
Memory Cache內存緩存(短期)前進后退頁面
Disk Cache磁盤緩存(長期)CSS/JS 文件緩存
Push CacheHTTP/2 推送緩存(會話級)服務器推送資源

*觸發強制刷新(Ctrl+F5)時會跳過所有緩存*


三、DNS 解析階段(DNS Lookup

  • 優化手段

    <!-- 預解析特定域名 -->
    <link rel="dns-prefetch" href="//cdn.example.com">

四、建立連接階段(TCP Handshake

  1. 三次握手建立 TCP 連接

    Client->Server: SYN
    Server->Client: SYN-ACK
    Client->Server: ACK
  2. TLS 握手(HTTPS)

    • 協商加密協議版本

    • 驗證證書有效性

    • 交換對稱加密密鑰


五、發送請求階段(HTTP Request

GET /index.html HTTP/1.1
Host: www.example.com
Accept: text/html
Cookie: session_id=abc123
  • 關鍵過程

    • 攜帶 Cookie 等身份信息

    • 檢查?Connection: keep-alive?復用連接

    • 處理?Content-Encoding?壓縮格式


六、響應處理階段(Response Processing

  1. 狀態碼處理

    // 常見狀態碼處理邏輯
    switch(statusCode) {case 301:handleRedirect(response.headers.Location);break;case 404:show404Page();break;case 500:logServerError();break;
    }
  2. 解壓響應體

    • 自動處理 gzip/deflate 壓縮


七、解析渲染階段(Rendering

  • 關鍵阻塞點

    • <script>?標簽會阻塞 DOM 構建(除非添加?async/defer

    • CSS 文件會阻塞渲染樹合成(CSSOM 構建)


八、持續通信階段(Keep-Alive

  • TCP 連接復用

    // HTTP/1.1 默認開啟 keep-alive
    // 同一域名最多維持 6 個 TCP 連接(瀏覽器差異)
  • HTTP/2 多路復用

    • 單個連接并行傳輸多個請求

    • 頭部壓縮優化


關鍵性能優化點

  1. 減少 DNS 查詢(使用 dns-prefetch)

  2. 復用 TCP 連接(合理配置 keep-alive)

  3. 壓縮資源體積(Gzip/Brotli)

  4. 避免渲染阻塞(CSS 內聯/JS 異步加載)

  5. 利用 CDN 加速(減少網絡延遲)

理解整個流程可以幫助前端開發者針對性優化關鍵路徑,提升頁面加載性能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/905310.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/905310.shtml
英文地址,請注明出處:http://en.pswp.cn/news/905310.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Matlab基于SSA-MVMD麻雀算法優化多元變分模態分解

Matlab基于SSA-MVMD麻雀算法優化多元變分模態分解 目錄 Matlab基于SSA-MVMD麻雀算法優化多元變分模態分解效果一覽基本介紹程序設計參考資料效果一覽 基本介紹 Matlab基于SSA-MVMD麻雀算法優化多元變分模態分解 可直接運行 分解效果好 適合作為創新點(Matlab完整源碼和數據),…

Gatsby知識框架

一、Gatsby 基礎概念 1. 核心特性 基于React的靜態站點生成器&#xff1a;使用React構建&#xff0c;輸出靜態HTML/CSS/JS GraphQL數據層&#xff1a;統一的數據查詢接口 豐富的插件系統&#xff1a;超過2000個官方和社區插件 高性能優化&#xff1a;自動代碼分割、預加載、…

【論信息系統項目的資源管理】

論信息系統項目的資源管理 前言一、規劃好資源管理&#xff0c;為保證項目完成做好人員規劃二、估算活動資源&#xff0c;為制訂項目進度計劃提供資源需求三、獲取項目資源&#xff0c;組建一個完備的項目團隊四、建設項目團隊&#xff0c;提高工作能力&#xff0c;促進團隊成員…

idea Maven 打包SpringBoot可執行的jar包

背景&#xff1a;當我們需要坐聯調測試的時候&#xff0c;需要對接前端同事&#xff0c;則需要打包成jar包直接運行啟動服務 需要將項目中的pom文件增加如下代碼配置&#xff1a; <build><plugins><plugin><groupId>org.springframework.boot</gr…

VScode 的插件本地更改后怎么生效

首先 vscode 的插件安裝地址為 C:\Users\%USERNAME%\.vscode\extensions 找到你的插件包進行更改 想要打印日志&#xff0c;用下面方法 vscode.window.showErrorMessage(console.log "${name}" exists.); 打印結果 找到插件&#xff0c;點擊卸載 然后點擊重新啟動 …

Python訓練營打卡——DAY24(2025.5.13)

目錄 一、元組 1. 通俗解釋 2. 元組的特點 3. 元組的創建 4. 元組的常見用法 二、可迭代對象 1. 定義 2. 示例 3. 通俗解釋 三、OS 模塊 1. 通俗解釋 2. 目錄樹 四、作業 1. 準備工作 2. 實戰代碼示例? 3. 重要概念解析 一、元組 是什么??&#xff1a;一種…

初入OpenCV

OpenCV簡介 OpenCV是一個開源的跨平臺計算機視覺庫&#xff0c;它實現了圖像處理和計算機視覺方面的很多通用算法。 應用場景&#xff1a; 目標識別&#xff1a;人臉、車輛、車牌、動物&#xff1b; 自動駕駛&#xff1b;醫學影像分析&#xff1b; 視頻內容理解分析&#xff…

訊聯云庫項目開發日志(一)

1、設計數據庫 2、寫基本框架 entity、controller、service、exception、utils、mapper mapper層&#xff1a; 生成了一系列的CRUD方法 工具類&#xff1a;線程安全的日期工具類、 ??參數校驗工具類? 線程安全的日期工具類??&#xff1a;主要用于 ??日期格式化&…

langchain學習

無門檻免費申請OpenAI ChatGPT API搭建自己的ChatGPT聊天工具 https://nuowa.net/872 基本概念 LangChain 能解決大模型的兩個痛點&#xff0c;包括模型接口復雜、輸入長度受限離不開自己精心設計的模塊。根據LangChain 的最新文檔&#xff0c;目前在 LangChain 中一共有六大…

Protobuf工具

#region 知識點一 什么是 Protobuf //Protobuf 全稱是 protocol - buffers&#xff08;協議緩沖區&#xff09; // 是谷歌提供給開發者的一個開源的協議生成工具 // 它的主要工作原理和我們之前做的自定義協議工具類似 // 只不過它更加的完善&…

zst-2001 上午題-歷年真題 軟件工程(38個內容)

CMM 軟件工程 - 第1題 b 軟件工程 - 第2題 c 軟件工程 - 第3題 c 軟件工程 - 第4題 b 軟件工程 - 第5題 b CMMI 軟件工程 - 第6題 0.未完成&#xff1a;未執行未得到目標。1.已執行&#xff1a;輸入-輸出實現支持2.已管理&#xff1a;過程制度化&#x…

軟考架構師考試-UML圖總結

考點 選擇題 2-4分 案例分析0~1題和面向對象結合考察&#xff0c;前幾年固定一題。近3次考試沒有出現。但還是有可能考。 UML圖概述 1.用例圖&#xff1a;描述系統功能需求和用戶&#xff08;參與者&#xff09;與系統之間的交互關系&#xff0c;聚焦于“做什么”。 2.類圖&…

數據結構(七)——圖

一、圖的定義與基本術語 1.圖的定義 圖G由頂點集V和邊集E組成&#xff0c;記為G(V,E)&#xff0c;其中V(G)表示圖G中頂點的有限非空集&#xff1b;E(G)表示圖G中頂點之間的關系&#xff08;邊&#xff09;的集合 注意&#xff1a;線性表可以是空表&#xff0c;樹可以是空樹&…

Android7 Input(六)InputChannel

概述: 本文講述Android Input輸入框架中 InputChannel的功能。從前面的講述&#xff0c;我們知道input系統服務最終將輸入事件寫入了InputChannel&#xff0c;而input屬于system_server進程&#xff0c;App屬于另外一個進程&#xff0c;當Input系統服務想要把事件傳遞給App進行…

【 Redis | 實戰篇 秒殺實現 】

目錄 前言&#xff1a; 1.全局ID生成器 2.秒殺優惠券 2.1.秒殺優惠券的基本實現 2.2.超賣問題 2.3.解決超賣問題的方案 2.4.基于樂觀鎖來解決超賣問題 3.秒殺一人一單 3.1.秒殺一人一單的基本實現 3.2.單機模式下的線程安全問題 3.3.集群模式下的線程安全問題 前言&…

如何用URDF文件構建機械手模型并與MoveIt集成

機械手URDF文件的編寫 我們用urdf文件來描述我們的機械手的外觀以及物理性能。這里為了簡便&#xff0c;就只用了基本的圓柱、立方體了。追求美觀的朋友&#xff0c;還可以用dae文件來描述機械手的外形。 import re def remove_comments(text):pattern r<!--(.*?)-->…

《構建社交應用的安全結界:雙框架對接審核API的底層邏輯與實踐》

用戶生成內容如潮水般涌來。從日常的生活分享&#xff0c;到激烈的觀點碰撞&#xff0c;這些內容賦予社交應用活力&#xff0c;也帶來管理難題。虛假信息、暴力言論、侵權內容等不良信息&#xff0c;如同潛藏的暗礁&#xff0c;威脅著社交平臺的健康生態。內容審核機制&#xf…

39:分類器流程

第一步 創建支持向量機分類器 create_class_svm (7, rbf, KernelParam, Nu, |ClassNames|, one-versus-one, principal_components, 5, SVMHandle) 第二步 添加樣本到分類器里 for ClassNumber : 0 to |ClassNames| - 1 by 1 *列出目錄下的所有文件 list_files (ReadPath…

LangChain對話鏈:打造智能多輪對話機器人

LangChain對話鏈:打造智能多輪對話機器人 目錄 LangChain對話鏈:打造智能多輪對話機器人ConversationChain 是什么核心功能與特點基本用法示例內存機制自定義提示詞應用場景與其他鏈的結合`SequentialChain` 是什么![在這里插入圖片描述](https://i-blog.csdnimg.cn/direct/0…

el-select 結合 el-tree:樹形下拉數據

一、單選 <template><div class"selectTree-wapper"><el-selectv-model"selectValue"placeholder"請選擇"popper-class"custom-el-select-class"ref"selectRef"clearableclear"clearHandle">&…