通過這個簡單的技巧讓我們的 JavaScript 代碼變得異常快

通過這個簡單的技巧讓我們的 JavaScript 代碼變得異常快

秘訣:了解JavaScript 虛擬機(VM)的內部工作原理。

首先,我們來談談像 V8 這樣的JavaScript 虛擬機(VM)。可以把它想象成我們的操作的大腦 —— 它將我們簡潔的代碼變成計算機可以理解和執行的東西。

好的、壞的代碼

讓我們深入研究一些代碼示例,看看好的、壞的和執行快的代碼。

緩慢的 JavaScript 示例:

function addProperty(obj, propName, value) {obj[propName] = value; // 這會改變對象的形狀
}
const responseObject = { user1: 1, user2: 2 };
addProperty(responseObject, 'user3', 3); // 添加新的屬性

是什么讓它變慢?

形狀更改:每次調用 addProperty 函數時,都會向對象添加一個新屬性。這會改變對象的“形狀”,即它包含的鍵變了,這反過來又會顛覆 JavaScript 引擎的優化。

添加或刪除屬性時,引擎可能必須丟棄以前的優化信息并重新開始。這種“形狀變化”就是操作緩慢的原因。

快速 JavaScript 示例:

function  createObject ( a, b, c ) { 
// 對象的形狀是固定的并且VM可以預測return { a, b, c }; 
} 
const dataObject = createObject ( 212,2344,43545);

是什么讓它如此快速?

可預測的形狀:

該對象是使用一組固定的屬性創建的。創建后沒有任何變化,更容易引擎優化。

隱藏類重用:

由于每次調用 createObject 時對象的形狀都是一致的,因此 JavaScript 引擎可以重用為此形狀創建的隱藏類。這種重用允許非常快速的屬性訪問,因為引擎確切地知道每個屬性在內存中的位置。

為什么對象形狀很重要:

當我們訪問對象的屬性時,引擎不想搜索所有屬性來找到它。相反,它想要直接訪問該屬性在內存中的位置。如果對象的形狀已知,引擎可以記住每個屬性所在的位置(這稱為“內聯緩存”)。但是,如果形狀發生變化(如上面的緩慢示例),引擎必須“重新學習”屬性位置,這要慢得多。

為了獲得最佳性能,特別是在頻繁訪問屬性的代碼關鍵部分,最好:

  • 創建對象時初始化所有屬性:即使某些屬性最初可能未定義。
  • 避免添加或刪除屬性:這可以保持對象的形狀穩定。
  • 盡可能重用對象形狀:創建始終生成具有相同屬性集的對象的工廠函數。

通過遵循這些實踐,我們可以幫助 JavaScript 引擎優化我們的代碼,從而加快執行速度。

常見的用例

當處理來自外部源的對象(例如 API 響應或 DOM 元素)時,在使用這些對象之前將它們規范化為一致的形狀對性能有益。這允許 JavaScript 引擎優化對這些對象的訪問,因為形狀(對象內的所有鍵)是可預測的并且不會改變。當我們頻繁讀取對象時,這種做法尤其有價值。

讓我們來看下面兩個常見的示例

通過 API 獲取用戶信息

慢速版本:

在慢速版本中,屬性被一一添加到對象中,這可能會導致 JavaScript 引擎由于形狀變化而取消對對象的訪問優化。

function fetchUserProfile(url) {fetch(url).then(response => response.json()).then(user => {const userProfile = {};if (user.name) {userProfile.name = user.name;}if (user.age) {userProfile.age = user.age;}if (user.email) {userProfile.email = user.email;}// ...處理更多的屬性return userProfile;});
}
快速版本:

在快速版本中,我們從一開始就創建一個具有已知形狀的對象,即使某些屬性可能未定義。這種一致性允許 JavaScript 引擎優化屬性訪問。

function fetchUserProfile(url) {return fetch(url).then(response => response.json()).then(user => {// 先定義對象中包含的所有的屬性const userProfile = {name: user.name || undefined,age: user.age || undefined,email: user.email || undefined,// ... 初始化更多屬性};return userProfile;});
}

在快速版本中,即使用戶對象不具有我們分配給 userProfile 的所有屬性,我們仍然使用其相應的值或未定義的值來定義我們期望的所有鍵。這樣,userProfile 的形狀保持一致,這有利于稍后訪問其屬性時的性能。

這種做法對于性能關鍵型應用程序至關重要,優化可以極大地提高執行速度。

如果上面的例子讓我們想起了什么,那是因為這個模式看起來像工廠模式,它遵循類似于工廠函數的原則,通過創建一個具有預定義形狀的對象,但它并不完全是這樣。在 JavaScript 中,工廠模式通常涉及構造并返回新對象的專用函數。當創建過程復雜或需要執行一些額外的設置工作時,工廠函數特別有用。

使用工廠模式

在給定的快速示例中,我們看到了一種創建具有一致形狀的對象的方法。為了使其與工廠模式更加一致,我們可以將對象創建封裝在專用函數中,如下所示:

function createUserProfile(name, age, email) {
// 通過工廠模式創建對象return {name: name || undefined,age: age || undefined,email: email || undefined,// ...};}function fetchUserProfile(url) {return fetch(url).then(response => response.json()).then(user => {return createUserProfile(user.name, user.age, user.email);});
}

在這個版本中,createUserProfile 是一個工廠函數,總是創建具有相同形狀的對象,這有利于優化。fetchUserProfile 函數使用此工廠創建一個新的 userProfile 對象。

使用DOM

現在讓我們討論另一個常見的示例,在使用 DOM 時,我們經常需要從 HTML 元素讀取信息,然后在應用程序中使用這些數據。保持對象形狀一致對于性能非常重要,尤其是當我們重復執行這些操作時。

下面的示例演示了對象形狀發生變化的慢速代碼示例,以及對象形狀可預測且一致的快速方法。

慢速代碼示例
function getUserData() {const userObject = {};const userName = document.querySelector('#input-name');if (nameElement) {userObject.name = nameElement.textContent;}const userAge = document.querySelector('#input-age');if (ageElement) {userObject.age = parseInt(ageElement.textContent);}// 每次調用此函數時,它可能會也可能不會添加新屬性// 這可能會導致對象形狀發生變化return userObject;
}
快速代碼示例
function createUserData(name = undefined, age = undefined) {
// 始終返回具有相同形狀的對象的工廠函數return { name, age };
}
function getUserData() {const userName = document.querySelector('#input-name');const userAge = parseInt(document.querySelector('#input-age')?.textContent);// 無論元素是否存在,對象的形狀都是一致的return createUserData(userName?.textContent, Number.isNaN(userAge) ? undefined : userAge);
}

在上面代碼中,createUserData 工廠函數確保返回的對象始終具有相同的形狀,這有利于 JavaScript 引擎的優化過程。getUserData 函數使用此工廠函數來創建配置文件數據對象,并通過提供 undefined 作為默認值來處理丟失的 DOM 元素,從而維護對象的形狀。

通過使用可選鏈接運算符 (?.) 和空合并運算符 (??),我們可以進一步細化該函數以處理 DOM 元素可能不存在的情況:

function getUserData() {const name = document.querySelector('#input-name')?.textContent ?? undefined;const ageText = document.querySelector('#input-age')?.textContent ?? undefined;const age = ageText ? parseInt(ageText) : undefined;// 對象的形狀一致return createUserData(name, age);
}

這種方法可以確保對象的形狀保持不變,即使在 DOM 中找不到某些元素,這在動態 Web 應用程序中很常見,因為有時元素尚未渲染或元素渲染順序不正確。

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

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

相關文章

免費圖書教材配套資料:Spark大數據技術與應用(第2版)

《Spark大數據技術與應用(第2版)》課程內容全面介紹了Spark大數據技術的相關知識,內容包含包括Spark概述、Scala基礎、Spark編程、Spark編程進階、Spark SQL結構化數據文件處理、Spark Streaming實時計算框架、Spark GraphX圖計算框架、Spark…

方法簽名【C#】

1條件: 簽名的作用:為了在眾多方法中找到匹配的方法。【自己想要的方法】類似明星的簽名。雖然2個人的名字一樣,但并不是同一個人,這就需要用到簽名的條件。 方法名稱:注意大小寫。 參數個數。 參數類型及順序&…

STL—next_permutation函數

目錄 1.next_permutation函數的定義 2.簡單使用 2.1普通數組全排列 2.2結構體全排列 2.3string 3.補充 1.next_permutation函數的定義 next_permutation函數會按照字母表順序生成給定序列的下一個較大的排列,直到整個序列為降序為止。與其相對的還有一個函數—…

實用工具推薦 | 在線制作電子書

?隨著互聯網的發展,越來越多的人開始關注知識的傳播和分享。而電子書作為一種方便攜帶、易于分享的形式,越來越受到人們的青睞。今天,就為大家推薦一款實用的工具——FLBOOK在線制作電子雜志平臺,讓你輕松在線制作電子書&#xf…

【python學習】基礎篇-常用模塊-re模塊:正則表達式高效操作字符串

在Python中,正則表達式主要通過re模塊來實現。以下是一些常用的正則表達式用法: 匹配值: pattern r\d # 匹配一個或多個數字 pattern r\b\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\b #匹配日期格式 pattern rhello # 匹配字符串“hello”\…

【LeetCode】挑戰100天 Day12(熱題+面試經典150題)

【LeetCode】挑戰100天 Day12(熱題面試經典150題) 一、LeetCode介紹二、LeetCode 熱題 HOT 100-142.1 題目2.2 題解 三、面試經典 150 題-143.1 題目3.2 題解 一、LeetCode介紹 LeetCode是一個在線編程網站,提供各種算法和數據結構的題目&…

HTTP客戶端警告:Going to buffer response body of large or unknown size

HTTP客戶端警告:Going to buffer response body of large or unknown size 點關注不迷路,歡迎再訪! 精簡博客內容,盡量已行業術語來分享。 努力做到對每一位認可自己的讀者負責。 幫助別人的同時更是豐富自己的良機。 目錄 HTTP客…

IAR為恩智浦S32M2提供全面支持,提升電機控制能力

IAR Embedded Workbench for Arm已全面支持恩智浦最新的S32系列,可加速軟件定義汽車的車身和舒適性應用的開發 瑞典烏普薩拉,2023年11月22日 – 嵌入式開發軟件和服務的全球領導者IAR現已全面支持恩智浦半導體(NXP Semiconductors&#xff0…

python腳本后臺執行

nohup python script.py &

CMS垃圾收集器深入解析

1.CMS的兩種模式與一種特殊策略 1.1Backgroud CMS(沒有并發失敗的情況) 1.1.1并發標記還能被整理成兩個流程 (1)初始標記 (2)并發標記(3)(4)在這個階段發生(3)并發預處理 (4)可中止的預處理 (5)重新標記 (6)并發清除 1.1.2為什么我們的并發標記細化之后還會額外有兩個流…

【pandas數據處理】數據結構

數據結構 Series基于列表創建數據結構自定義元素的行標簽基于字典創建數據結構 DataFrame對象基于列表創建數據結構設置參數來定義行列標簽基于字典 Series 一維數組對象,不僅包含數據元素,還包含一組與數據元素對應的行標簽。 基于列表創建數據結構 …

C++設計模式之工廠模式(下)——抽象工廠模式

抽象工廠模式 介紹示例示例使用運行結果抽象工廠模式的優缺點優點缺點 總結 介紹 抽象工廠模式是一種創建型設計模式,它提供了一種封裝一組相關或相互依賴對象的方式,而無需指定它們具體的類。它允許客戶端使用抽象接口來創建一系列相關的對象&#xff…

Jquery ajax 同步阻塞引起的UI線程阻塞的坑(loading圖片顯示不出來 )

Jquery ajax 同步阻塞引起的UI線程阻塞的坑(loading圖片顯示不出來,layer.load延遲)jax重新獲取數據刷新頁面功能,因為ajax屬于耗時操作,想在獲取數據且加載頁面時顯示加載遮罩層,結果發現了ajax的好多坑。…

Elasticsearch自動清理腳本

腳本 我在data下創建的腳本文件就叫:vi /data/clear_log.sh,內容如下 #!/bin/sh #獲取時間 time=`date +%Y-%m-%d %H:%M:%S` cipan=`df -h| grep sda3` #查詢磁盤使用率 liang=`df -h| grep sda3 |grep -v grep |awk {print $5}|tr -d

【數據結構】一題帶你出師鏈表!

🦄個人主頁:修修修也 🎏所屬專欄:數據結構 ??操作環境:Visual Studio 2022 題目鏈接 138. 隨機鏈表的復制https://leetcode.cn/problems/copy-list-with-random-pointer/ 題目描述 給你一個長度為 n 的鏈表,每個節點包含一個額外增加的隨機…

Make a BESD file from QTLtools output

Make a BESD file from QTLtools output # 根據基因名與變異rsid編號去重 library(tidyverse) library(readxl) qtltoolsnomi <- read_table("qtltoolsnomi.txt",col_names F) qtltoolsnomi %>% distinct(X1,X8, .keep_all TRUE) -> qtltool qtltool …

qml ParticleSystem3D使用介紹

在 Qt Quick 3D 中,ParticleSystem3D 是用來創建和控制3D粒子系統的元素。粒子系統是圖形編程中用于模擬液體、煙霧、火、星空等現象的技術,它通過生成大量小粒子來模擬這些效果。ParticleSystem3D 提供了一個框架,允許開發者定義粒子的各種屬性,如生命周期、速度、顏色、大…

王道p149 9.設樹B是一棵采用鏈式結構存儲的二叉樹,編寫一個把樹 B中所有結點的左、右子樹進行交換的函數。(c語言代碼實現)

本題代碼如下 void swap(tree* t) {if (*t){treenode* temp (*t)->lchild;(*t)->lchild (*t)->rchild;(*t)->rchild temp;swap(&(*t)->lchild);swap(&(*t)->rchild);} } 完整測試代碼 #include<stdio.h> #include<stdlib.h> typed…

C#string.Format的一些使用

C#中的string.Format方法是一個用于格式化字符串的功能強大的方法。它允許您通過將占位符替換為實際的值來創建格式化的字符串。 一、基本語法是&#xff1a; string.Format(format, arg0, arg1, arg2, ...) 其中&#xff0c; format是一個字符串&#xff0c;其中包含要格式…

Java常用類

目錄 包裝類 裝箱和拆箱 包裝類型和String的轉換&#xff0c;包裝類的常用方法 包裝類 裝箱和拆箱 package com.edu.wrapper;public class Interger01 {//演示int<-->Integer的裝箱和拆箱//手動裝箱int n1100;Integer integer new Integer(n1);Integer integer01 In…