1.NodeJS的優缺點
優點:
· 高并發(最重要的優點)
· 適合I/O密集型應用
缺點:
· 不適合CPU密集型應用;CPU密集型應用給Node帶來的挑戰主要是:由于JavaScript單線程的原因,如果有長時間運行的計算(比如大循環),將會導致CPU時間片不能釋放,使得后續I/O無法發起;
解決方案:分解大型運算任務為多個小任務,使得運算能夠適時釋放,不阻塞I/O調用的發起;
· 只支持單核CPU,不能充分利用CPU
· 可靠性低,一旦代碼某個環節崩潰,整個系統都崩潰
原因:單進程,單線程
解決方案:(1)Nnigx反向代理,負載均衡,開多個進程,綁定多個端口;
(2)開多個進程監聽同一個端口,使用cluster模塊;
· 開源組件庫質量參差不齊,更新快,向下不兼容
· Debug不方便,錯誤沒有stack trace
2.文件上傳的優化
- 文件壓縮。對圖片、視頻等資源,使用前端壓縮(如使用 compressorjs)減少上傳體積。
- 分片上傳(大文件)。將大文件拆分成多個小塊分片上傳。
- 并發上傳控制。控制并發數(如最多同時上傳 3 個文件)防止資源占用過高;使用
Promise.allSettled
、任務隊列或限制上傳并發工具(如p-limit
)。
3.切片上傳的要點
核心思想是:將大文件拆成若干小片段分批上傳,最終由后端合并還原成完整文件。
- 切片策略:切片大小設置,然后使用 File.slice() API 切割
- 文件唯一標識(fileId):為了正確合并和續傳,需要為文件生成唯一標識(通常基于文件名 + 文件大小 + hash)
- 上傳控制邏輯:順序或并發上傳切片,通常采用 并發上傳(5~10 并發) 提高性能;同時攜帶元信息,每個切片應攜帶fileId、當前分片索引(chunkIndex)、分片總數(totalChunks)、是否為最后一塊、可選的 MD5 校驗值
- 后端配合
4.ES6 特性
①:let和const
-
let
: 塊級作用域,允許變量重新賦值 -
const
: 塊級作用域,不允許重新賦值(但對象內容可變)
②:symbol
Symbol是ES6中引入的一種新的基本數據類型,用于表示一個獨一無二的值,不能與其他數據類型進行運算。它是JavaScript中的第七種數據類型,與undefined、null、Number(數值)、String(字符串)、Boolean(布爾值)、Object(對象)并列。
③:模板字符串
- 在ES6之前,處理模板字符串:通過“\”和“+”來構建模板
- 對ES6來說:用
${}
來界定;反引號(``)
直接搞定;
<script>url="x"// es6之前let html="<div>"+" <a>"+url+"</a>"+"</div>";//es6let eshtml=`<div><a>${url}</a></div>`
</script>
④:解構表達式
解構賦值是對賦值運算符的擴展。它是一種針對數組或者對象進行模式匹配,然后對其中的變量進行賦值。字符串、以及ES6新增的Map和Set?都可以使用解構表達式
//數組解構let [a,b,c] = [1,2,3];
console.log(a,b,c); //1,2,3let [a,b,c] = [1,,3];
console.log(a,b,c); //1,undefined,3let [a,,b] = [1,2,3];
console.log(a,b);//1,3let [a,..b] = [1,2,3]; //...是剩余運算符,表示賦值運算符右邊除第一個值外剩余的都賦值給b
console.log(a,b);//1,[2,3]//對象解構
let obj = { name: "山里", age: 18, sex: "m"
};let { name, age, sex } = obj;
console.log(name, age, sex); //'山里' 18 'm'let { name: myName, age: myAge, sex: mySex } = obj; //自定義變量名
console.log(myName, myAge, mySex); //'山里' 18 'm'
⑤:Map和Set屬于es6新增加的對象
- Map對象用于保存鍵值對,任何值JavaScript支持的值都可以作為一個鍵(key)或者一個值(value)。
- Set對象和Map對象類似,但它存儲不是鍵值對。類似數組,但它的每個元素都是唯一的。
const set = new Set([1, 2, 2, 3]); // 去重
const map = new Map([['a', 1], ['b', 2]]);
⑥:函數增強
- 默認參數
//默認參數
function greet(name = '游客') {console.log(`你好,${name}`);
}
-
箭頭函數。箭頭函數實現了一種更加簡潔的書寫方式。箭頭函數內部沒有
arguments
,也沒有prototype
屬性,所以不能用new
關鍵字調用箭頭函數。
箭頭函數和普通函數最大的區別在于其內部this永遠指向其父級對象的this。(重點)
let add = (a,b) => {return a+b;
}
let print = () => {console.log('hi');
}
let fn = a => a * a;
//當只有一個參數時,括號可以省略,函數體只有單行return語句時,大括號也可以省略。
⑦:類(Class)
class
?作為對象的模板被引入ES6,你可以通過?class?
關鍵字定義類。class?
的本質依然是一個函數。
//類的定義和繼承
class Person {constructor(name) {this.name = name;}sayHi() {console.log(`Hi, I'm ${this.name}`);}
}class Student extends Person {constructor(name, grade) {super(name);this.grade = grade;}
}
⑧:模塊化(Module)
優點:1.防止命名沖突;2.復用性強
// a.js
export const PI = 3.14;
export default function add(a, b) { return a + b; }// b.js
import add, { PI } from './a.js';
⑨:Promise 異步處理
const p = new Promise((resolve, reject) => {setTimeout(() => resolve('成功'), 1000);
});
p.then(result => console.log(result));
5. async-await 和 Promise的關系
async/await
和 Promise
是 JavaScript 中處理異步操作的兩種方式。其中,async/await
是建立在 Promise 之上的語法糖,
特性 | Promise | async/await |
---|---|---|
語法形式 | .then() / .catch() | async 函數 + await |
可讀性 | 回調鏈(可能嵌套過多) | 更像同步代碼,結構清晰 |
錯誤處理 | .catch() | try...catch |
基礎依賴 | 原生特性 | 構建于 Promise 之上 |
// Promise 寫法
function getData() {return new Promise((resolve, reject) => {setTimeout(() => resolve('數據已獲取'), 1000);});
}getData().then(res => {console.log(res);}).catch(err => {console.error(err);});
// async/await 寫法
function getData() {return new Promise((resolve, reject) => {setTimeout(() => resolve('數據已獲取'), 1000);});
}async function fetchData() {try {const res = await getData(); // 等待 Promise 完成console.log(res);} catch (err) {console.error(err);}
}fetchData();//await 后面跟的是一個 Promise
//async/await 實際上是對 Promise 的封裝與優化
6.async-await原理
async/await
?是基于?Promise
?的語法糖,使得異步代碼看起來像同步代碼。async
?函數返回一個?Promise
?對象,await
?表達式用于等待一個?Promise
?完成。
async/await
?的底層實現可以類比于生成器(Generator)函數和自動執行器。生成器函數可以在執行過程中暫停和恢復,這為實現異步流程控制提供了可能。
7.箭頭函數和普通函數
特性 | 普通函數 | 箭頭函數 |
---|---|---|
this 指向 | 動態綁定,由調用方式決定 | 靜態綁定,取決于定義時所在作用域 |
arguments 對象 | 有 arguments 對象 | 沒有 arguments ,可用 rest 參數代替 |
構造函數 | 可作為構造函數(new Fn() ) | ? 不可作為構造函數,不能 new |
原型 prototype | 有 .prototype 屬性 | 沒有 .prototype 屬性 |
代碼簡潔性 | 相對冗長 | 更加簡潔,適合寫匿名函數或回調 |
能否綁定 this | 可使用 bind , call , apply 綁定 | 無效,this 永遠固定(詞法作用域) |
*this 指向:普通函數:調用時決定 this。
箭頭函數:定義時決定 this
(繼承外層作用域)
8.lodash的深拷貝怎么實現
在JavaScript中,我們經常需要復制對象。但是,JavaScript的對象復制通常只是淺復制,這意味著它只復制對象的最頂層屬性,而不復制嵌套對象或數組的內部元素。這就是為什么我們有時需要深拷貝的原因。深拷貝將復制對象的所有層級,包括嵌套的對象和數組。
在使用 Lodash 時,可以通過 _.cloneDeep
方法實現 深拷貝(deep copy),這是 Lodash 提供的內置方法,用于遞歸地克隆一個值,包括嵌套的對象、數組等復雜數據結構。
9.對象環引用的檢測
①:設置檢查標記。可以給每個對象設置一個標記;或者使用 WeakSet
代替顯式打標。
②:將對象引用地址存入數組,檢測是否已存在。可以改進用?Set
代替數組。
10.vue中的computed和watch
①:computed
(計算屬性)
-
作用:基于響應式依賴進行緩存的派生計算
-
特點:
-
返回一個值
-
僅在依賴變化時重新計算
-
用于模板中展示或復雜邏輯封裝
-
-
<template><div>總價:{{ totalPrice }}</div> </template><script setup> import { ref, computed } from 'vue';const price = ref(100); const count = ref(2);// 自動依賴 price 和 count,且具備緩存 const totalPrice = computed(() => price.value * count.value); </script>
②:watch
(偵聽器)
-
作用:在數據變化時執行副作用邏輯
-
特點:
-
適合執行異步操作、手動處理邏輯
-
可以偵聽多個源或深層屬性
-
-
<script setup> import { ref, watch } from 'vue';const searchText = ref('');// 監聽輸入內容變化,做防抖搜索等副作用處理 watch(searchText, (newVal, oldVal) => {console.log(`搜索內容從 "${oldVal}" 變為 "${newVal}"`);// 可調用 API 等操作 }); </script>
11.reactive
在 Vue 3 中,reactive
是 Composition API 中用于創建響應式對象的核心方法。它可以將一個普通的 JavaScript 對象轉換為響應式對象,從而在數據發生變化時自動更新視圖。
與 ref
的區別:
特性 | reactive | ref |
---|---|---|
用于 | 對象、數組、嵌套結構 | 原始值(字符串、數字等)或任意值 |
響應式訪問 | 直接訪問屬性 | .value 獲取/設置 |
結構深度響應 | 深層響應 | ?深層對象需搭配 reactive |
// reactive 示例
const obj = reactive({ count: 1 });
obj.count++; // 自動響應視圖更新// ref 示例
const num = ref(1);
num.value++; // 注意:需要 .value
12.vue2和vue3的區別
①:響應式系統的改變
Vue2 使用 Object.defineProperty
實現響應式,無法直接監聽數組下標變動或對象屬性的添加/刪除。而 Vue3 改為使用 Proxy
,可以實現對對象任意屬性的監聽,性能更高、限制更少,也更易于維護。
②:組合式 API 的引入
Vue2 使用“選項式 API”,即通過 data
、methods
、computed
、watch
等分散定義組件邏輯,導致邏輯難以復用和維護。
Vue3 引入了“組合式 API”,通過 setup()
函數配合 ref
、reactive
、computed
等函數來組織邏輯,更加靈活,便于邏輯復用和 TypeScript 支持。
③:性能優化
④:TypeScript 支持增強
⑤:新特性的引入
13.模板和JSX
- JSX 是?JavaScript?XML 的縮寫,是 React 框架中的一種語法擴展。它允許開發者在 JavaScript 代碼中直接編寫類似 HTML 的語法,從而更直觀地構建用戶界面。
- 模板 (Template) 通常是指在前端框架中使用的一種定義 UI 結構的方式。它們通常與特定的框架綁定,例如?Vue.js 中的模板語法,Angular 中的模板語法等。
①:JSX 的優點
更強的 JavaScript 集成:JSX 是 JavaScript 的一部分,可以在 JSX 代碼中編寫任意 JavaScript 表達式。這個特性使得組件邏輯和視圖可以緊密結合。
單文件組件:使用 JSX 時,組件的模板、邏輯和樣式通常在同一個文件中,這使得組件更加自包含,易于管理和重用。
React 生態系統:JSX 是 React 的核心部分,因此使用 JSX 可以更好地利用 React 提供的各種工具和庫。
②:JSX 的缺點
學習曲線:對于沒有 React 經驗的開發者來說,JSX 可能有一定的學習難度,尤其是在理解 JavaScript 和 JSX 之間的轉換時。
可讀性:雖然 JSX 使得 JavaScript 和模板代碼混合在一起,但對于習慣于分離視圖和邏輯的開發者來說,這種方式可能會降低代碼的可讀性。
③:模板的優點
分離關注點:模板語法通常將視圖和邏輯分開,保持代碼的清晰和可維護性。例如,在 Vue.js 中,模板負責定義視圖,而邏輯和數據綁定在組件腳本部分處理。
直觀的語法:模板語法通常類似于 HTML,這使得前端開發者尤其是設計師更容易上手和理解。
框架支持:模板語法通常與框架緊密集成,提供豐富的指令和綁定機制,簡化了常見的 UI 操作。
④:模板的缺點
靈活性較差:由于模板語法通常是框架特定的,它們在處理復雜邏輯時可能不如 JSX 靈活。
單文件組件限制:雖然模板語法也支持單文件組件,但在某些框架中,模板、邏輯和樣式分離在不同的部分,這可能會導致管理上的不便。
?
14.vite和Webpack
15.常用git命令
git init? ?
初始化本地 Git 倉庫- git clone <url>? ? ??克隆遠程倉庫到本地
- git status? ? ? ? ?查看當前工作區狀態
- git add .? ? ? ??添加所有修改過的文件到暫存區
- git commit -m "說明"???? ? ? ? ? 提交暫存區到本地倉庫????
- ?git branch? ? ? ?查看本地分支
- git branch <分支名>? ? ? ?創建新分支
- ?git checkout <分支名>? ? ? ? ??切換分支
- git push? ? ? ? ?推送本地改動到遠程
- git log? ? ? ? ?查看提交歷史
16.Vue修改數據后能獲取最新的dom?
在 Vue 中,修改數據后不能立即獲取最新的 DOM,因為 Vue 的 DOM 更新是異步的。這意味著在你更改響應式數據后,Vue 會在下一個“tick”(事件循環的下一個微任務隊列中)統一執行 DOM 更新。
正確獲取最新 DOM 的方法:使用 nextTick
這是 Vue 提供的官方方式,等 DOM 更新后再執行回調。
import { nextTick } from 'vue'await nextTick()
// 或
nextTick(() => {// DOM 已更新
})
17.后端傳遞過來十條數據,前端需要制作一個垂直的無限循環滾動展示的效果。如何實現?
使用 CSS 動畫 + JavaScript DOM 克隆機制。將列表復制一份接在原始列表之后,形成“頭尾連接”。然后使用 CSS 動畫持續向上滾動整個容器,當滾動到底部(即一輪滾完),立即跳回頂部,繼續滾動。
<template><div class="news-wrapper"><ul class="news-list" ref="newsList"><li v-for="(news, index) in renderList" :key="index">{{ news }}</li></ul></div>
</template><script setup>
import { ref, onMounted } from 'vue'const news = ["新聞1", "新聞2", "新聞3", "新聞4", "新聞5","新聞6", "新聞7", "新聞8", "新聞9", "新聞10"
]const renderList = [...news, ...news] // 克隆一份實現無縫滾動
</script><style scoped>
.news-wrapper {height: 300px;overflow: hidden;
}
.news-list {animation: scrollUp 10s linear infinite;padding: 0;margin: 0;
}
.news-list li {height: 30px;line-height: 30px;border-bottom: 1px solid #eee;list-style: none;
}@keyframes scrollUp {0% { transform: translateY(0); }100% { transform: translateY(-50%); }
}
</style>