खोज…


परिचय

जावास्क्रिप्ट, किसी भी भाषा की तरह, हमें कुछ भाषा सुविधाओं के उपयोग में विवेकपूर्ण होना चाहिए। कुछ सुविधाओं का अधिक उपयोग प्रदर्शन को कम कर सकता है, जबकि कुछ तकनीकों का उपयोग प्रदर्शन को बढ़ाने के लिए किया जा सकता है।

टिप्पणियों

याद रखें कि समयपूर्व अनुकूलन सभी बुराई की जड़ है। पहले स्पष्ट, सही कोड लिखें, फिर यदि आपको प्रदर्शन की समस्याएं हैं, तो सुधार के लिए विशिष्ट क्षेत्रों की तलाश के लिए एक प्रोफाइलर का उपयोग करें। समय का अनुकूलन कोड बर्बाद न करें जो समग्र प्रदर्शन को सार्थक तरीके से प्रभावित नहीं कर रहा है।

नापना, नापना, नापना। प्रदर्शन अक्सर प्रतिवाद हो सकता है, और समय के साथ बदल सकता है। अब जो तेजी है वह भविष्य में नहीं हो सकती है, और आपके उपयोग के मामले पर निर्भर कर सकती है। सुनिश्चित करें कि आपके द्वारा किए गए कोई भी अनुकूलन वास्तव में सुधार कर रहे हैं, प्रदर्शन को नुकसान नहीं पहुंचा रहे हैं, और यह परिवर्तन सार्थक है।

प्रदर्शन-महत्वपूर्ण कार्यों में कोशिश / पकड़ से बचें

कुछ जावास्क्रिप्ट इंजन (उदाहरण के लिए, Node.js का वर्तमान संस्करण और इग्निशन + टर्बोफैन से पहले क्रोम के पुराने संस्करण) उन फ़ंक्शन पर ऑप्टिमाइज़र नहीं चलाते हैं, जिनमें एक कोशिश / कैच ब्लॉक होता है।

यदि आपको प्रदर्शन-महत्वपूर्ण कोड में अपवादों को संभालने की आवश्यकता है, तो यह कुछ मामलों में तेज / पकड़ को एक अलग फ़ंक्शन में रखने के लिए तेज़ हो सकता है। उदाहरण के लिए, यह फ़ंक्शन कुछ कार्यान्वयनों द्वारा अनुकूलित नहीं किया जाएगा:

function myPerformanceCriticalFunction() {
    try {
        // do complex calculations here
    } catch (e) {
        console.log(e);
    }
}

हालांकि, आप धीमे कोड को एक अलग फ़ंक्शन (जिसे अनुकूलित किया जा सकता है) में स्थानांतरित करने की try कर सकते हैं और इसे try ब्लॉक के अंदर से कॉल कर सकते हैं।

// This function can be optimized
function doCalculations() {
    // do complex calculations here
}

// Still not always optimized, but it's not doing much so the performance doesn't matter
function myPerformanceCriticalFunction() {
    try {
        doCalculations();
    } catch (e) {
        console.log(e);
    }
}

यहाँ एक jsPerf बेंचमार्क है जो अंतर दिखा रहा है: https://jsperf.com/try-catch-deoptimization । अधिकांश ब्राउज़रों के वर्तमान संस्करण में, यदि कोई हो, तो बहुत अंतर नहीं होना चाहिए, लेकिन क्रोम और फ़ायरफ़ॉक्स, या IE के कम हाल के संस्करणों में, कोशिश / कैच के अंदर एक सहायक फ़ंक्शन को कॉल करने वाले संस्करण के तेज़ होने की संभावना है।

ध्यान दें कि इस तरह के अनुकूलन को सावधानीपूर्वक और वास्तविक प्रमाण के साथ आपके कोड को प्रोफाइलिंग के आधार पर किया जाना चाहिए। जैसे ही जावास्क्रिप्ट इंजन बेहतर हो जाता है, यह मदद करने के बजाय, या बिल्कुल भी कोई फर्क नहीं पड़ता है (लेकिन इस कारण के लिए कोड को जटिल कर रहा है) से कोई प्रदर्शन नहीं हो सकता है। चाहे वह मदद करता हो, दर्द करता हो, या कोई फर्क नहीं पड़ता है, बहुत सारे कारकों पर निर्भर कर सकता है, इसलिए हमेशा अपने कोड पर प्रभाव को मापें। यह सभी ऑप्टिमाइज़ेशन के लिए सही है, लेकिन विशेष रूप से इस तरह के माइक्रो-ऑप्टिमाइज़ेशन जो कंपाइलर / रनटाइम के निम्न-स्तरीय विवरणों पर निर्भर करते हैं।

भारी-कंप्यूटिंग कार्यों के लिए एक मेमोइज़र का उपयोग करें

यदि आप एक फ़ंक्शन का निर्माण कर रहे हैं जो प्रोसेसर (या तो क्लाइंटसाइड या सर्वरसाइड) पर भारी हो सकता है, तो आप एक मेमोइज़र पर विचार करना चाह सकते हैं जो पिछले फ़ंक्शन के निष्पादन और उनके लौटे मूल्यों का कैश है । यह आपको यह जांचने की अनुमति देता है कि किसी फ़ंक्शन के पैरामीटर पहले पारित किए गए थे या नहीं। याद रखें, शुद्ध कार्य वे हैं जो एक इनपुट देते हैं, एक समान अद्वितीय आउटपुट लौटाते हैं और उनके दायरे के बाहर दुष्प्रभाव पैदा नहीं करते हैं, इसलिए आपको ऐसे कार्यों में संस्मरण नहीं जोड़ना चाहिए जो अप्रत्याशित हों या बाहरी संसाधनों पर निर्भर हों (जैसे AJAX कॉल या बेतरतीब ढंग से लौटाया गया मान)।

मान लें कि मेरा एक पुनरावर्ती कार्य है:

function fact(num) {
  return (num === 0)? 1 : num * fact(num - 1);
}

यदि मैं उदाहरण के लिए 1 से 100 तक के छोटे मान पास करता हूं, तो कोई समस्या नहीं होगी, लेकिन एक बार जब हम गहराई में जाने लगते हैं, तो हम कॉल स्टैक को उड़ा सकते हैं या हम जिस जावास्क्रिप्ट इंजन में यह कर रहे हैं उसके लिए प्रक्रिया को थोड़ा दर्दनाक बना सकते हैं; खासकर अगर इंजन टेल-कॉल ऑप्टिमाइज़ेशन के साथ नहीं गिना जाता है (हालांकि डगलस क्रॉकफोर्ड कहते हैं कि देशी ईएस 6 में टेल-कॉल ऑप्टिमाइज़ेशन शामिल है)।

हम अपने स्वयं के शब्दकोश को 1 से देव-कोड तक कठिन कोड दे सकते हैं, जो उनके संबंधित तथ्यों के साथ जानते हैं लेकिन, मुझे यकीन नहीं है कि मैं सलाह दूंगा! चलो एक ज्ञापन बनाएँ, हम करेंगे?

var fact = (function() {
  var cache = {}; // Initialise a memory cache object
  
  // Use and return this function to check if val is cached
  function checkCache(val) {
    if (val in cache) {
      console.log('It was in the cache :D');
      return cache[val]; // return cached
    } else {
      cache[val] = factorial(val); // we cache it
      return cache[val]; // and then return it
    }
    
    /* Other alternatives for checking are:
    || cache.hasOwnProperty(val) or !!cache[val]
    || but wouldn't work if the results of those
    || executions were falsy values.
    */
  }

  // We create and name the actual function to be used
  function factorial(num) {
    return (num === 0)? 1 : num * factorial(num - 1);
  } // End of factorial function

  /* We return the function that checks, not the one
  || that computes because  it happens to be recursive,
  || if it weren't you could avoid creating an extra
  || function in this self-invoking closure function.
  */
  return checkCache; 
}());

अब हम इसका उपयोग शुरू कर सकते हैं:

यह कैसे किया जाता है

अब जब कि मैं, मैं क्या किया पर प्रतिबिंबित करने के लिए अगर मैं संख्या से 1 के बजाय घटती से वेतन वृद्धि के लिए गए थे शुरू, मैं factorials के सभी 1 से कैश में संख्या को रिकर्सिवली कैश्ड किया जा सकता था, लेकिन मैं आप के लिए छोड़ देंगे कि।

यह बहुत अच्छा है लेकिन क्या होगा अगर हमारे पास कई पैरामीटर हैं ? यह एक समस्या है? काफी नहीं, हम तर्कों सरणी पर JSON.stringify () या मानों की एक सूची का उपयोग करने जैसी कुछ अच्छी चालें भी कर सकते हैं जो फ़ंक्शन (ऑब्जेक्ट-उन्मुख दृष्टिकोणों के लिए) पर निर्भर करेगा। यह सभी तर्कों और निर्भरताओं के साथ एक अद्वितीय कुंजी उत्पन्न करने के लिए किया जाता है।

हम एक फ़ंक्शन भी बना सकते हैं जो अन्य कार्यों को "याद दिलाता है", समान गुंजाइश अवधारणा का उपयोग पहले की तरह (एक नया फ़ंक्शन जो मूल का उपयोग करता है और कैश ऑब्जेक्ट तक पहुंच है) लौटाता है:

चेतावनी: ES6 सिंटैक्स, यदि आपको यह पसंद नहीं है, तो प्रतिस्थापित करें ... कुछ भी नहीं और var args = Array.prototype.slice.call(null, arguments); छल; const बदलें और var के साथ जाने दें, और दूसरी चीजें जो आप पहले से जानते हैं।

function memoize(func) {
  let cache = {};

  // You can opt for not naming the function
  function memoized(...args) {
    const argsKey = JSON.stringify(args);
    
    // The same alternatives apply for this example
    if (argsKey in cache) {
      console.log(argsKey + ' was/were in cache :D');
      return cache[argsKey];
    } else {
      cache[argsKey] = func.apply(null, args); // Cache it
      return cache[argsKey]; // And then return it
    }
  }

  return memoized; // Return the memoized function
}

अब ध्यान दें कि यह कई तर्कों के लिए काम करेगा, लेकिन मुझे लगता है कि ऑब्जेक्ट-ओरिएंटेड विधियों में बहुत अधिक उपयोग नहीं होगा, आपको निर्भरता के लिए एक अतिरिक्त ऑब्जेक्ट की आवश्यकता हो सकती है। इसके अलावा, func.apply(null, args) को func(...args) से बदला जा सकता है क्योंकि func.apply(null, args) बाद उन्हें ऐरे फॉर्म के बजाय अलग से भेजा जाएगा। इसके अलावा, सिर्फ संदर्भ के लिए, एक तर्क के रूप में फ़ंक करने के लिए एक सरणी से गुजरना तब तक काम नहीं करेगा जब तक कि आप Function.prototype.apply उपयोग न करें जैसा कि मैंने किया था।

उपरोक्त विधि का उपयोग करने के लिए आप बस:

const newFunction = memoize(oldFunction);

// Assuming new oldFunction just sums/concatenates:
newFunction('meaning of life', 42);
// -> "meaning of life42"

newFunction('meaning of life', 42); // again
// => ["meaning of life",42] was/were in cache :D
// -> "meaning of life42"

अपने कोड को बेंचमार्क करना - निष्पादन समय को मापना

अधिकांश प्रदर्शन युक्तियां जेएस इंजनों की वर्तमान स्थिति पर बहुत निर्भर हैं और यह केवल एक निश्चित समय में प्रासंगिक होने की उम्मीद है। प्रदर्शन अनुकूलन का मूलभूत नियम यह है कि आपको पहले से ही अनुकूलन करने की कोशिश करने से पहले उपाय करना चाहिए, और फिर से निर्धारित अनुकूलन के बाद फिर से मापना चाहिए।

कोड निष्पादन समय को मापने के लिए, आप विभिन्न समय माप उपकरणों का उपयोग कर सकते हैं जैसे:

प्रदर्शन इंटरफ़ेस जो दिए गए पृष्ठ के लिए समय-संबंधित प्रदर्शन जानकारी का प्रतिनिधित्व करता है (केवल ब्राउज़रों में उपलब्ध है)।

Node.js पर process.hrtime आपको [सेकंड, नैनोसेकंड] ट्यूपल्स के रूप में समय की जानकारी देता है। बिना तर्क के कॉल किया गया यह एक मनमाना समय देता है लेकिन पहले से लौटाए गए मान के साथ कहा जाता है क्योंकि यह दो निष्पादन के बीच के अंतर को वापस करता है।

कंसोल टाइमर्स कंसोल। टाइम console.time("labelName") एक टाइमर शुरू करता है जिसका उपयोग आप ट्रैक कर सकते हैं कि किसी ऑपरेशन में कितना समय लगता है। आप प्रत्येक टाइमर को एक अद्वितीय लेबल नाम देते हैं, और इसमें दिए गए पृष्ठ पर 10,000 तक टाइमर हो सकते हैं। जब आप एक ही नाम के साथ console.timeEnd("labelName") , तो ब्राउज़र दिए गए नाम के लिए टाइमर को समाप्त कर देगा और मिलीसेकंड में समय का उत्पादन करेगा, जो कि टाइमर शुरू होने के बाद समाप्त हो गया था। समय () और टाइम-एंड () से जुड़े तार मेल खाने चाहिए अन्यथा टाइमर समाप्त नहीं होगा।

Date.now फ़ंक्शन Date.now() मिलीसेकंड में वर्तमान टाइमस्टैम्प लौटाता है, जो कि 1 जनवरी 1970 से 00:00:00 यूटीसी के बाद से अब तक के समय का एक संख्या प्रतिनिधित्व है। विधि अब () दिनांक की एक स्थिर विधि है, इसलिए आप इसे हमेशा Date.now () के रूप में उपयोग करते हैं।

उदाहरण 1 का उपयोग करते हुए: performance.now()

इस उदाहरण में हम अपने कार्य के निष्पादन के लिए बीते हुए समय की गणना करने जा रहे हैं, और हम प्रदर्शन () विधि का उपयोग करने जा रहे हैं जो एक DOMHecResTimeStamp को लौटाता है, जो मिलीसेकंड में मापा जाता है, एक मिलीसेकंड के एक हजारवें हिस्से तक।

let startTime, endTime;

function myFunction() {
    //Slow code you want to measure
}

//Get the start time
startTime = performance.now();

//Call the time-consuming function
myFunction();

//Get the end time
endTime = performance.now();

//The difference is how many milliseconds it took to call myFunction()
console.debug('Elapsed time:', (endTime - startTime));

कंसोल में परिणाम कुछ इस तरह दिखाई देगा:

Elapsed time: 0.10000000009313226

performance.now() का उपयोग करें। performance.now() में मिलीसेकंड के एक हजारवें तक सटीकता के साथ ब्राउज़रों में उच्चतम सटीकता है, लेकिन सबसे कम संगतता है

उदाहरण 2 का उपयोग कर: Date.now()

इस उदाहरण में हम एक बड़े सरणी (1 मिलियन मान) के आरंभ के लिए बीते हुए समय की गणना करने जा रहे हैं, और हम Date.now() विधि का उपयोग करने जा रहे हैं

let t0 = Date.now(); //stores current Timestamp in milliseconds since 1 January 1970 00:00:00 UTC
let arr = []; //store empty array
for (let i = 0; i < 1000000; i++) { //1 million iterations
   arr.push(i); //push current i value
}
console.log(Date.now() - t0); //print elapsed time between stored t0 and now

उदाहरण 3 का उपयोग कर: console.time("label") और console.timeEnd("label")

इस उदाहरण में हम उदाहरण 2 के समान कार्य कर रहे हैं, लेकिन हम console.time("label") का उपयोग करने जा रहे हैं। console.time("label") और console.timeEnd("label") और console.timeEnd("label") विधियों

console.time("t"); //start new timer for label name: "t"
let arr = []; //store empty array
for(let i = 0; i < 1000000; i++) { //1 million iterations
   arr.push(i); //push current i value
}
console.timeEnd("t"); //stop the timer for label name: "t" and print elapsed time

process.hrtime() 4 का उपयोग कर छूट process.hrtime()

Node.js कार्यक्रमों में यह खर्च किए गए समय को मापने का सबसे सटीक तरीका है।

let start = process.hrtime();

// long execution here, maybe asynchronous

let diff = process.hrtime(start);
// returns for example [ 1, 2325 ]
console.log(`Operation took ${diff[0] * 1e9 + diff[1]} nanoseconds`);
// logs: Operation took 1000002325 nanoseconds

ग्लोबल्स, विशेषताओं और अनुक्रमित मूल्यों के लिए स्थानीय चर को प्राथमिकता दें

जावास्क्रिप्ट इंजन पहली बार बड़े दायरे में अपनी खोज का विस्तार करने से पहले स्थानीय दायरे में चर की तलाश करते हैं। यदि किसी ऐरे में वेरिएबल इंडेक्सेड वैल्यू है, या ऐसोसिएटिव एरे में एट्रिब्यूट है, तो कंटेंट मिलने से पहले यह पेरेंट ऐरे के लिए दिखेगा।

प्रदर्शन-महत्वपूर्ण कोड के साथ काम करते समय इसके निहितार्थ हैं। उदाहरण के for पाश के लिए एक आम ले लो:

var global_variable = 0;
function foo(){
    global_variable = 0;
    for (var i=0; i<items.length; i++) {
        global_variable += items[i];
    }
}

में हर यात्रा के लिए for पाश, इंजन देखने होगा items , देखने length आइटम भीतर विशेषता, देखने items फिर से, मूल्य सूचकांक पर देखने i के items अंत में देखने, और फिर global_variable , पहले वैश्विक क्षेत्र की जाँच से पहले स्थानीय गुंजाइश कोशिश कर रहा।

उपरोक्त फ़ंक्शन का एक प्रदर्शनकारी फिर से लिखना है:

function foo(){
    var local_variable = 0;
    for (var i=0, li=items.length; i<li; i++) {
        local_variable += items[i];
    }
    return local_variable;
}

लूप के for फिर से लिखे गए प्रत्येक पुनरावृत्ति के for , इंजन li , लुकअप items , इंडेक्स i पर मान को देखने, और local_variable देखने के लिए, इस बार केवल स्थानीय स्कोप की जांच करने की आवश्यकता होगी।

वस्तुओं को पुनः बनाने के बजाय पुन: उपयोग करें

उदाहरण ए

var i,a,b,len;
a = {x:0,y:0}
function test(){ // return object created each call
    return {x:0,y:0};
}
function test1(a){ // return object supplied 
    a.x=0;
    a.y=0;
    return a;
}   

for(i = 0; i < 100; i ++){ // Loop A
   b = test();
}

for(i = 0; i < 100; i ++){ // Loop B
   b = test1(a);
}

लूप बी, लूप ए की तुलना में 4 (400%) गुना तेज है

प्रदर्शन कोड में एक नई वस्तु बनाने के लिए यह बहुत अक्षम है। लूप ए कॉल फ़ंक्शन test() जो हर कॉल पर एक नई वस्तु देता है। बनाई गई वस्तु को हर पुनरावृत्ति को छोड़ दिया जाता है, लूप बी test1() को कॉल करता है जिसके लिए वस्तु रिटर्न की आवश्यकता होती है। इस प्रकार यह एक ही वस्तु का उपयोग करता है और एक नई वस्तु के आवंटन से बचा जाता है, और अत्यधिक GC हिट करता है। (प्रदर्शन परीक्षण में जीसी शामिल नहीं थे)

उदाहरण बी

var i,a,b,len;
a = {x:0,y:0}
function test2(a){
    return {x : a.x * 10,y : a.x * 10};
}   
function test3(a){
    a.x= a.x * 10;
    a.y= a.y * 10;
    return a;
}  
for(i = 0; i < 100; i++){  // Loop A
    b = test2({x : 10, y : 10});
}
for(i = 0; i < 100; i++){ // Loop B
    a.x = 10;
    a.y = 10;
    b = test3(a);                
}

लूप बी लूप ए की तुलना में 5 (500%) गुना तेज है

DOM अपडेट्स को सीमित करें

जब एक ब्राउज़र वातावरण में चलाया जाता है तो जावास्क्रिप्ट में देखी गई एक सामान्य गलती DOM को आवश्यकता से अधिक बार अपडेट कर रही है।

यहाँ मुद्दा यह है कि DOM इंटरफ़ेस में प्रत्येक अपडेट ब्राउज़र को स्क्रीन को फिर से प्रस्तुत करने का कारण बनता है। यदि कोई अपडेट पृष्ठ में एक तत्व के लेआउट को बदलता है, तो पूरे पृष्ठ के लेआउट को फिर से गणना करने की आवश्यकता होती है, और यह सबसे सरल मामलों में भी बहुत अधिक प्रदर्शन-भारी होता है। एक पृष्ठ को फिर से ड्राइंग करने की प्रक्रिया को रिफ्लो के रूप में जाना जाता है और इससे ब्राउज़र धीरे-धीरे चल सकता है या अप्रतिसादी हो सकता है।

दस्तावेज़ को बार-बार अपडेट करने का परिणाम किसी सूची में आइटम जोड़ने के निम्न उदाहरण के साथ चित्रित किया गया है।

निम्नलिखित दस्तावेज पर विचार करें जिसमें <ul> तत्व शामिल है:

<!DOCTYPE html>
<html>
    <body>
        <ul id="list"></ul>
    </body>
</html>

हम 5000 वस्तुओं को 5000 बार लूपिंग सूची में जोड़ते हैं (आप प्रभाव बढ़ाने के लिए शक्तिशाली कंप्यूटर पर बड़ी संख्या के साथ यह कोशिश कर सकते हैं)।

var list = document.getElementById("list");
for(var i = 1; i <= 5000; i++) {             
    list.innerHTML += `<li>item ${i}</li>`;  // update 5000 times
}

इस मामले में, एक ही डोम अपडेट में सभी 5000 परिवर्तनों को बैच कर प्रदर्शन में सुधार किया जा सकता है।

var list = document.getElementById("list");
var html = "";
for(var i = 1; i <= 5000; i++) {
    html += `<li>item ${i}</li>`;
}
list.innerHTML = html;     // update once

फंक्शन document.createDocumentFragment()document.createDocumentFragment() का उपयोग लूप द्वारा बनाए गए HTML के लिए एक हल्के कंटेनर के रूप में किया जा सकता है। यह विधि कंटेनर तत्व की innerHTML संपत्ति को संशोधित करने की तुलना में थोड़ा तेज है (जैसा कि नीचे दिखाया गया है)।

var list = document.getElementById("list");
var fragment = document.createDocumentFragment();
for(var i = 1; i <= 5000; i++) {
    li = document.createElement("li");
    li.innerHTML = "item " + i;
    fragment.appendChild(li);
    i++;
}
list.appendChild(fragment);

अशक्त के साथ वस्तु गुण को आरम्भ करना

सभी आधुनिक जावास्क्रिप्ट जेआईटी अपेक्षित वस्तु संरचनाओं के आधार पर कोड का अनुकूलन करने की कोशिश कर रहे हैं। Mdn से कुछ टिप।

सौभाग्य से, वस्तुएं और गुण अक्सर "पूर्वानुमेय" होते हैं, और ऐसे मामलों में उनकी अंतर्निहित संरचना भी पूर्वानुमेय हो सकती है। जेआईटी इस पर भरोसा कर सकते हैं ताकि पूर्वानुमान की पहुंच और तेज हो सके।

ऑब्जेक्ट को प्रेडिक्टेबल बनाने का सबसे अच्छा तरीका एक कंस्ट्रक्टर में पूरी संरचना को परिभाषित करना है। इसलिए यदि आप ऑब्जेक्ट निर्माण के बाद कुछ अतिरिक्त गुण जोड़ने जा रहे हैं, तो उन्हें एक निर्माणकर्ता में null परिभाषित करें। यह आशावादी को अपने पूरे जीवन चक्र के लिए वस्तु व्यवहार की भविष्यवाणी करने में मदद करेगा। हालाँकि सभी कंपाइलरों के अलग-अलग ऑप्टिमाइज़र होते हैं, और प्रदर्शन में वृद्धि अलग-अलग हो सकती है, लेकिन कुल मिलाकर एक कंस्ट्रक्टर में सभी गुणों को परिभाषित करने के लिए यह अच्छा अभ्यास है, तब भी जब उनका मूल्य अभी तक ज्ञात नहीं है।

कुछ परीक्षण के लिए समय। अपने परीक्षण में, मैं लूप के लिए कुछ वर्ग उदाहरणों का एक बड़ा सरणी बना रहा हूं। लूप के भीतर, मैं सरणी आरंभीकरण से पहले सभी ऑब्जेक्ट के "x" गुण को एक ही स्ट्रिंग असाइन कर रहा हूं। यदि कंस्ट्रक्टर "x" प्रॉपर्टी को null के साथ इनिशियलाइज़ करता है, तो एरे हमेशा अतिरिक्त प्रोसेस करते हुए भी बेहतर प्रोसेस करता है।

यह कोड है:

function f1() {
    var P = function () {
        this.value = 1
    };
    var big_array = new Array(10000000).fill(1).map((x, index)=> {
        p = new P();
        if (index > 5000000) {
            p.x = "some_string";
        }

        return p;
    });
    big_array.reduce((sum, p)=> sum + p.value, 0);
}

function f2() {
    var P = function () {
        this.value = 1;
        this.x = null;
    };
    var big_array = new Array(10000000).fill(1).map((x, index)=> {
        p = new P();
        if (index > 5000000) {
            p.x = "some_string";
        }

        return p;
    });
    big_array.reduce((sum, p)=> sum + p.value, 0);
}


(function perform(){
    var start = performance.now();
    f1();
    var duration = performance.now() - start;

    console.log('duration of f1  ' + duration);


    start = performance.now();
    f2();
    duration = performance.now() - start;

    console.log('duration of f2 ' + duration);
})()

यह क्रोम और फ़ायरफ़ॉक्स के लिए परिणाम है।

       FireFox     Chrome
 --------------------------
 f1      6,400      11,400
 f2      1,700       9,600   

जैसा कि हम देख सकते हैं, प्रदर्शन सुधार दोनों के बीच बहुत भिन्न हैं।

संख्याओं के उपयोग में सुसंगत रहें

यदि इंजन आपके मूल्यों के लिए विशिष्ट छोटे प्रकार का उपयोग कर रहा है, तो आप सही अनुमान लगा सकते हैं, यह निष्पादित कोड को अनुकूलित करने में सक्षम होगा।

इस उदाहरण में, हम इस तुच्छ फ़ंक्शन का उपयोग किसी सरणी के तत्वों को जोड़ेंगे और इसमें लगने वाले समय का उत्पादन करेंगे:

// summing properties
var sum = (function(arr){
        var start = process.hrtime();
        var sum = 0;
        for (var i=0; i<arr.length; i++) {
                sum += arr[i];
        }
        var diffSum = process.hrtime(start);
        console.log(`Summing took ${diffSum[0] * 1e9 + diffSum[1]} nanoseconds`);
        return sum;
})(arr);

चलो एक सरणी बनाते हैं और तत्वों का योग करते हैं:

var     N = 12345,
        arr = [];
for (var i=0; i<N; i++) arr[i] = Math.random();

परिणाम:

Summing took 384416 nanoseconds

अब, चलो ऐसा ही करते हैं लेकिन केवल पूर्णांकों के साथ:

var     N = 12345,
        arr = [];
for (var i=0; i<N; i++) arr[i] = Math.round(1000*Math.random());

परिणाम:

Summing took 180520 nanoseconds

आधे से अधिक पूर्णांकों का योग यहां बना।

इंजन आपके पास जावास्क्रिप्ट में समान प्रकारों का उपयोग नहीं करते हैं। जैसा कि आप शायद जानते हैं, जावास्क्रिप्ट में सभी नंबर IEEE754 डबल सटीक फ़्लोटिंग पॉइंट नंबर हैं, पूर्णांक के लिए कोई विशिष्ट उपलब्ध प्रतिनिधित्व नहीं है। लेकिन इंजन, जब वे भविष्यवाणी कर सकते हैं कि आप केवल पूर्णांक का उपयोग करते हैं, प्रतिनिधित्व के लिए एक अधिक कॉम्पैक्ट और तेज़ का उपयोग कर सकते हैं, उदाहरण के लिए, लघु पूर्णांक।

इस तरह का अनुकूलन गणना या डेटा गहन अनुप्रयोगों के लिए विशेष रूप से महत्वपूर्ण है।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow