亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

緩慢或卡頓的網(wǎng)站是業(yè)余愛(ài)好者的標(biāo)志,而流暢、優(yōu)化的體驗(yàn)會(huì)讓用戶感到高興,并使專業(yè)人士脫穎而出。

但創(chuàng)建真正高性能的網(wǎng)絡(luò)應(yīng)用程序充滿了陷阱。錯(cuò)誤比比皆是,它們可能會(huì)拖慢JavaScript的速度,而您甚至沒(méi)有意識(shí)到這一點(diǎn)。微小的疏忽會(huì)讓你的代碼變得臃腫,并悄悄地一點(diǎn)一點(diǎn)地降低速度。

這是怎么回事?

事實(shí)證明,我們有很多常見(jiàn)的方式會(huì)無(wú)意中減慢 JavaScript 的速度。隨著時(shí)間的推移,可能會(huì)阻礙網(wǎng)站性能。

這些錯(cuò)誤是可以避免的。

今天,我們重點(diǎn)關(guān)注可能會(huì)悄悄減慢 JavaScript 和 Node.js 應(yīng)用程序速度的 19 個(gè)性能陷阱。我們將通過(guò)說(shuō)明性示例和可操作的解決方案來(lái)探索導(dǎo)致這些問(wèn)題的原因,以優(yōu)化您的代碼。

識(shí)別并消除這些危害是打造讓用戶滿意的流暢網(wǎng)絡(luò)體驗(yàn)的關(guān)鍵。那么,讓我們深入了解一下吧!

1. 不正確的變量聲明和作用域

第一次學(xué)習(xí) JavaScript 時(shí),很容易在全局聲明所有變量。然而,這會(huì)導(dǎo)致未來(lái)出現(xiàn)問(wèn)題。讓我們看一個(gè)例子:

// globals.js
var color = 'blue';
function printColor() {
  console.log(color); 
}
printColor(); // Prints 'blue'

登錄后復(fù)制

這工作正常,但想象一下如果我們加載另一個(gè)腳本:

// script2.js
var color = 'red';
printColor(); // Prints 'red'!

登錄后復(fù)制

因?yàn)閏olor是全局的,所以script2.js覆蓋了它!要解決此問(wèn)題,請(qǐng)盡可能在函數(shù)內(nèi)部聲明變量:

function printColor() {
  var color = 'blue'; // local variable
  
  console.log(color);
}
printColor(); // Prints 'blue'

登錄后復(fù)制

現(xiàn)在,其他腳本的更改不會(huì)影響printColor.

不必要時(shí)在全局范圍內(nèi)聲明變量是一種反模式。嘗試將全局變量限制為配置常量。對(duì)于其他變量,請(qǐng)?jiān)诒M可能小的范圍內(nèi)進(jìn)行本地聲明。

2. 低效的 DOM 操作

更新 DOM 元素時(shí),批量更改而不是一次操作一個(gè)節(jié)點(diǎn)。考慮這個(gè)例子:

const ul = document.getElementById('list');
for (let i = 0; i < 10; i++) {
  const li = document.createElement('li');
  li.textContent = i;
  
  ul.appendChild(li);
}

登錄后復(fù)制

這將逐一附加列表項(xiàng)。最好先構(gòu)建一個(gè)字符串然后設(shè)置.innerHTML:

const ul = document.getElementById('list');
let html = '';
for (let i = 0; i < 10; i++) {
  html += `<li>${i}</li>`; 
}
ul.innerHTML = html;

登錄后復(fù)制

構(gòu)建字符串可以最大限度地減少回流。我們更新 DOM 一次而不是 10 次。

對(duì)于多個(gè)更新,構(gòu)建更改,然后在最后應(yīng)用?;蛘吒玫氖?,使用 DocumentFragment 批量追加。

3. 過(guò)多的 DOM 操作

頻繁的DOM更新會(huì)降低性能??紤]一個(gè)將消息插入頁(yè)面的聊天應(yīng)用程序。

反面例子:

// New message received
const msg = `<div>${messageText}</div>`;
chatLog.insertAdjacentHTML('beforeend', msg);

登錄后復(fù)制

這天真地插入到每條消息上。最好是限制更新:

正確示例:

let chatLogHTML = '';
const throttleTime = 100; // ms
// New message received  
chatLogHTML += `<div>${messageText}</div>`;
// Throttle DOM updates
setTimeout(() => {
  chatLog.innerHTML = chatLogHTML;
  chatLogHTML = ''; 
}, throttleTime);

登錄后復(fù)制

現(xiàn)在,我們最多每 100 毫秒更新一次,從而保持 DOM 操作較低。

對(duì)于高度動(dòng)態(tài)的 UI,請(qǐng)考慮像 React 這樣的虛擬 DOM 庫(kù)。這些最大限度地減少了使用虛擬表示的 DOM 操作。

4.缺乏活動(dòng)委托

將事件偵聽(tīng)器附加到許多元素會(huì)產(chǎn)生不必要的開(kāi)銷??紤]一個(gè)每行都有刪除按鈕的表:

反面例子:

const rows = document.querySelectorAll('table tr');
rows.forEach(row => {
  const deleteBtn = row.querySelector('.delete');  
  deleteBtn.addEventListener('click', handleDelete);
});

登錄后復(fù)制

這會(huì)為每個(gè)刪除按鈕添加一個(gè)偵聽(tīng)器。需要更好地使用事件委托:

正確示例:

const table = document.querySelector('table');
table.addEventListener('click', e => {
  if (e.target.classList.contains('delete')) {
    handleDelete(e);
  }
});

登錄后復(fù)制

現(xiàn)在,.net 上只有一個(gè)偵聽(tīng)器,更少的內(nèi)存開(kāi)銷。

事件委托利用事件冒泡。一個(gè)偵聽(tīng)器可以處理來(lái)自多個(gè)后代的事件。只要適用,就使用委派。

5. 低效的字符串連接

在循環(huán)中連接字符串時(shí),性能會(huì)受到影響??紤]這段代碼:

let html = '';
for (let i = 0; i < 10; i++) {
  html += '<div>' + i + '</div>';
}

登錄后復(fù)制

創(chuàng)建新字符串需要分配內(nèi)存。最好使用數(shù)組:

const parts = [];
for (let i = 0; i < 10; i++) {
  parts.push('<div>', i, '</div>');
}
const html = parts.join('');

登錄后復(fù)制

構(gòu)建數(shù)組可以最大限度地減少中間字符串。.join()最后連接一次。

對(duì)于多個(gè)字符串添加,請(qǐng)使用數(shù)組連接。另外,請(qǐng)考慮嵌入值的模板文字。

6. 未優(yōu)化的循環(huán)

JavaScript 中的循環(huán)經(jīng)常會(huì)導(dǎo)致性能問(wèn)題。一個(gè)常見(jiàn)的錯(cuò)誤是重復(fù)訪問(wèn)數(shù)組長(zhǎng)度:

反面例子:

const items = [/*...*/];
for (let i = 0; i < items.length; i++) {
  // ...
}

登錄后復(fù)制

冗余檢查.length會(huì)抑制優(yōu)化。

正確示例:

const items = [/*...*/];  
const len = items.length;
for (let i = 0; i < len; i++) {
  // ...
}

登錄后復(fù)制

緩存長(zhǎng)度可以提高速度。其他優(yōu)化包括將不變量提升到循環(huán)之外、簡(jiǎn)化終止條件以及避免迭代內(nèi)昂貴的操作。

7. 不必要的同步操作

JavaScript 的異步功能是一個(gè)關(guān)鍵優(yōu)勢(shì)。但要小心阻塞 I/O!例如:

反面例子:

const data = fs.readFileSync('file.json'); // blocks!

登錄后復(fù)制

這會(huì)在從磁盤(pán)讀取時(shí)停止執(zhí)行。相反,如果使用回調(diào)或承諾:

正確示例:

fs.readFile('file.json', (err, data) => {
  // ...
});

登錄后復(fù)制

現(xiàn)在,事件循環(huán)在讀取文件時(shí)繼續(xù)。對(duì)于復(fù)雜的流程,async/await簡(jiǎn)化異步邏輯。避免同步操作以防止阻塞。

8. 阻止事件循環(huán)

JavaScript 使用單線程事件循環(huán)。阻止它會(huì)停止執(zhí)行。一些常見(jiàn)的攔截器:

繁重的計(jì)算任務(wù)

同步輸入/輸出

未優(yōu)化的算法

例如:

function countPrimes(max) {
  // Unoptimized loop
  for (let i = 0; i <= max; i++) {
    // ...check if prime...
  }
}
countPrimes(1000000); // Long running!

登錄后復(fù)制

這會(huì)同步執(zhí)行,并阻止其他事件。避免:

推遲不必要的工作

批量數(shù)據(jù)處理

使用工作線程

尋找優(yōu)化機(jī)會(huì)

保持事件循環(huán)順利運(yùn)行。定期分析以捕獲阻塞代碼。

9. 錯(cuò)誤處理效率低下

在 JavaScript 中正確處理錯(cuò)誤至關(guān)重要。但要小心性能陷阱!

反面例子:

try {
  // ...
} catch (err) {
  console.error(err); // just logging
}

登錄后復(fù)制

這會(huì)捕獲錯(cuò)誤但不采取糾正措施。未處理的錯(cuò)誤通常會(huì)導(dǎo)致內(nèi)存泄漏或數(shù)據(jù)損壞。

正確示例:

try {
  // ...
} catch (err) {
  console.error(err);
  
  // Emit error event 
  emitError(err); 
  
  // Nullify variables
  obj = null;
  
  // Inform user
  showErrorNotice();
}

登錄后復(fù)制

記錄還不夠!清理工件、通知用戶并考慮恢復(fù)選項(xiàng)。使用 Sentry 等工具來(lái)監(jiān)控生產(chǎn)中的錯(cuò)誤。明確處理所有錯(cuò)誤。

10. 內(nèi)存泄漏

當(dāng)內(nèi)存被分配但從未釋放時(shí),就會(huì)發(fā)生內(nèi)存泄漏。隨著時(shí)間的推移,泄漏會(huì)累積并降低性能。

JavaScript 中的常見(jiàn)來(lái)源包括:

未清理的事件監(jiān)聽(tīng)器

對(duì)已刪除 DOM 節(jié)點(diǎn)的過(guò)時(shí)引用

不再需要的緩存數(shù)據(jù)

閉包中的累積狀態(tài)

例如:

function processData() {
  const data = [];
  // Use closure to accumulate data
  return function() {
    data.push(getData()); 
  }
}
const processor = processData();
// Long running...keeps holding reference to growing data array!

登錄后復(fù)制

數(shù)組不斷變大,但從未被清除。修理:

使用弱引用

清理事件監(jiān)聽(tīng)器

刪除不再需要的引用

限制關(guān)閉狀態(tài)大小

監(jiān)視內(nèi)存使用情況并觀察增長(zhǎng)趨勢(shì)。在泄漏堆積之前主動(dòng)消除泄漏。

11. 過(guò)度使用依賴項(xiàng)

雖然 npm 提供了無(wú)窮無(wú)盡的選擇,但請(qǐng)抵制過(guò)度導(dǎo)入的沖動(dòng)!每個(gè)依賴項(xiàng)都會(huì)增加包大小和攻擊面。

反面例子:

import _ from 'lodash';
import moment from 'moment'; 
import validator from 'validator';
// etc...

登錄后復(fù)制

為次要實(shí)用程序?qū)胝麄€(gè)庫(kù)。最好根據(jù)需要挑選助手:

正確示例:

import cloneDeep from 'lodash/cloneDeep';
import { format } from 'date-fns';
import { isEmail } from 'validator';

登錄后復(fù)制

只導(dǎo)入您需要的內(nèi)容。定期檢查依賴關(guān)系以刪除未使用的依賴關(guān)系。保持捆綁精簡(jiǎn)并最大限度地減少依賴性。

12. 緩存不足

緩存允許通過(guò)重用先前的結(jié)果來(lái)跳過(guò)昂貴的計(jì)算。但它經(jīng)常被忽視。

反面例子:

function generateReport() {
  // Perform expensive processing
  // to generate report data... 
}
generateReport(); // Computes
generateReport(); // Computes again!

登錄后復(fù)制

由于輸入沒(méi)有更改,因此可以緩存報(bào)告:

正確示例:

let cachedReport;
function generateReport() {
  if (cachedReport) {
    return cachedReport;
  }
  cachedReport = // expensive processing...
  return cachedReport; 
}

登錄后復(fù)制

現(xiàn)在,重復(fù)調(diào)用速度很快。

13. 未優(yōu)化的數(shù)據(jù)庫(kù)查詢

與數(shù)據(jù)庫(kù)交互時(shí),低效的查詢可能會(huì)降低性能。需要避免的一些問(wèn)題:

反面例子:

// No indexing
db.find({name: 'John', age: 35}); 
// Unecessary fields
db.find({first: 'John', last:'Doe', email:'[email protected]'}, {first: 1, last: 1});
// Too many separate queries
for (let id of ids) {
  const user = db.find({id});
}

登錄后復(fù)制

這無(wú)法利用索引、檢索未使用的字段并執(zhí)行過(guò)多的查詢。

正確示例:

// Use index on 'name' 
db.find({name: 'John'}).hint({name: 1});
// Only get 'email' field
db.find({first: 'John'}, {email: 1}); 
// Get users in one query
const users = db.find({
  id: {$in: ids} 
});

登錄后復(fù)制

分析并解釋計(jì)劃。戰(zhàn)略性地創(chuàng)建索引。避免多次零散的查詢。優(yōu)化數(shù)據(jù)存儲(chǔ)交互。

14. Promise 中錯(cuò)誤處理不當(dāng)

Promise 簡(jiǎn)化了異步代碼。但未經(jīng)處理的拒絕就是無(wú)聲的失??!

反面例子:

function getUser() {
  return fetch('/user')
    .then(r => r.json()); 
}
getUser();

登錄后復(fù)制

如果fetch拒絕,異常就不會(huì)被注意到。

正確示例:

function getUser() {
  return fetch('/user')
    .then(r => r.json())
    .catch(err => console.error(err));
} 
getUser();

登錄后復(fù)制

鏈接.catch()可以正確處理錯(cuò)誤。

15. 同步網(wǎng)絡(luò)操作

網(wǎng)絡(luò)請(qǐng)求應(yīng)該是異步的。但有時(shí)會(huì)使用同步變體:

反面例子:

const data = http.getSync('http://example.com/data'); // blocks!

登錄后復(fù)制

這會(huì)在請(qǐng)求期間停止事件循環(huán)。相反,使用回調(diào):

正確示例:

http.get('http://example.com/data', res => {
  // ...
});

登錄后復(fù)制

或者:

fetch('http://example.com/data')
  .then(res => res.json())
  .then(data => {
    // ...
  });

登錄后復(fù)制

異步網(wǎng)絡(luò)請(qǐng)求允許在等待響應(yīng)時(shí)進(jìn)行其他處理。避免同步網(wǎng)絡(luò)調(diào)用。

16. 低效的文件 I/O 操作

讀/寫(xiě)文件同步阻塞。例如:

反面例子:

const contents = fs.readFileSync('file.txt'); // blocks!

登錄后復(fù)制

這會(huì)在磁盤(pán) I/O 期間停止執(zhí)行。

正確示例:

fs.readFile('file.txt', (err, contents) => {
  // ...
});
// or promises
fs.promises.readFile('file.txt')
   .then(contents => {
     // ...  
   });

登錄后復(fù)制

這允許事件循環(huán)在文件讀取期間繼續(xù)。

對(duì)于多個(gè)文件,使用流:

function processFiles(files) {
  for (let file of files) {
    fs.createReadStream(file)
      .pipe(/*...*/);
  }
}

登錄后復(fù)制

避免同步文件操作。使用回調(diào)、promise 和流。

17. 忽略性能分析和優(yōu)化

在出現(xiàn)明顯問(wèn)題之前,很容易忽視性能。但優(yōu)化應(yīng)該持續(xù)進(jìn)行!首先使用分析工具進(jìn)行測(cè)量:

瀏覽器開(kāi)發(fā)工具時(shí)間線

Node.js 分析器

第三方分析器

即使性能看起來(lái)不錯(cuò),這也揭示了優(yōu)化機(jī)會(huì):

// profile.js
function processOrders(orders) {
  orders.forEach(o => {
    // ...
  });
}
processOrders(allOrders);

登錄后復(fù)制

分析器顯示processOrders需要 200 毫秒。

分析指導(dǎo)優(yōu)化。制定績(jī)效預(yù)算,如果超出則失敗。經(jīng)常測(cè)量并明智地優(yōu)化。

18. 不利用緩存機(jī)制

緩存通過(guò)避免重復(fù)工作來(lái)提高速度。但它經(jīng)常被遺忘。

反面例子:

// Compute expensive report
function generateReport() {
  // ...heavy processing...
}
generateReport(); // Computes
generateReport(); // Computes again!

登錄后復(fù)制

相同的輸入總是產(chǎn)生相同的輸出。我們應(yīng)該緩存:

正確示例:

// Cache report contents
const cache = {};
function generateReport() {
  if (cache.report) {
    return cache.report;
  }
  const report = // ...compute...
  cache.report = report;
  return report;
}

登錄后復(fù)制

現(xiàn)在,重復(fù)調(diào)用速度很快。

19. 不必要的代碼重復(fù)

重復(fù)的代碼會(huì)損害可維護(hù)性和可優(yōu)化性。

function userStats(user) {
  const name = user.name;
  const email = user.email;
  
  // ...logic...
}
function orderStats(order) {
  const name = order.customerName;
  const email = order.customerEmail;
  // ...logic... 
}

登錄后復(fù)制

提取是重復(fù)的。我們重來(lái):

function getCustomerInfo(data) {
  return {
    name: data.name, 
    email: data.email
  };
}
function userStats(user) {
  const { name, email } = getCustomerInfo(user);
  
  // ...logic...
}
function orderStats(order) {
  const { name, email } = getCustomerInfo(order);
  // ...logic...
}

登錄后復(fù)制

現(xiàn)在,它只定義一次。

結(jié)論

優(yōu)化 JavaScript 應(yīng)用程序性能是一個(gè)迭代過(guò)程。通過(guò)學(xué)習(xí)有效的實(shí)踐并勤于分析,可以顯著提高速度。

需要關(guān)注的關(guān)鍵領(lǐng)域包括最大限度地減少 DOM 更改、利用異步技術(shù)、消除阻塞操作、減少依賴性、利用緩存以及刪除不需要的重復(fù)。

以上就是代碼運(yùn)行慢?避免這19個(gè)常見(jiàn)的JavaScript和Node.js錯(cuò)誤,讓你的程序高速狂飆的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注www.92cms.cn其它相關(guān)文章!

分享到:
標(biāo)簽:代碼 常見(jiàn) 狂飆 運(yùn)行 錯(cuò)誤
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定