বেনাম ফাংশন ব্যবহার কার্যকারিতা প্রভাবিত করে?


89

আমি ভাবছিলাম, জাভাস্ক্রিপ্টে নামযুক্ত ফাংশন এবং বেনাম ফাংশন ব্যবহারের মধ্যে পারফরম্যান্সের পার্থক্য রয়েছে?

for (var i = 0; i < 1000; ++i) {
    myObjects[i].onMyEvent = function() {
        // do something
    };
}

বনাম

function myEventHandler() {
    // do something
}

for (var i = 0; i < 1000; ++i) {
    myObjects[i].onMyEvent = myEventHandler;
}

প্রথমটি পরিপাটি হয় যেহেতু এটি আপনার কোডটি খুব কম ব্যবহার করা ফাংশন দিয়ে বিশৃঙ্খলা সৃষ্টি করে না, তবে আপনি কি সেই ফাংশনটিকে একাধিকবার পুনরায় ঘোষণা দিচ্ছেন তা কি গুরুত্বপূর্ণ?


আমি জানি এটি কোনও প্রশ্নে নেই, তবে কোড-পরিষ্কার-পরিচ্ছন্নতা / স্বচ্ছতার ক্ষেত্রে আমি মনে করি যে সঠিক পথটি মাঝখানে কোথাও রয়েছে। বিরলভাবে ব্যবহৃত শীর্ষ-স্তরের ফাংশনগুলির "বিশৃঙ্খলা" বিরক্তিকর, তবে এটি হ'ল ভারী নেস্টেড কোড যা বেনামে ফাংশনগুলিতে অনেকগুলি নির্ভর করে যা তাদের অনুরোধের সাথে লাইনে ঘোষিত হয় (নোড.জেএস কলব্যাক হেল্ক ভাবেন)। প্রাক্তন এবং উত্তরোত্তর উভয়ই ডিবাগিং / সম্পাদন ট্রেসিংকে কঠিন করে তুলতে পারে।
জ্যাক বি

নীচের কর্মক্ষমতা পরীক্ষাগুলি কয়েক হাজার পুনরাবৃত্তির জন্য ফাংশনটি চালায়। আপনি যদি যথেষ্ট পরিমাণে পার্থক্য দেখতে পান তবে বেশিরভাগ ব্যবহারের ক্ষেত্রে এই আদেশের পুনরাবৃত্তিতে এটি করা হবে না। সুতরাং আপনার প্রয়োজন অনুসারে যা কিছু চয়ন করা ভাল এবং এই বিশেষ ক্ষেত্রেটির জন্য কর্মক্ষমতা উপেক্ষা করা ভাল।
ব্যবহারকারী

@ নিকফ অবশ্যই এটি খুব পুরানো প্রশ্ন, তবে নতুন আপডেট হওয়া উত্তরটি দেখুন
চন্দন পাসুনুরী

উত্তর:


89

এখানে পারফরম্যান্স সমস্যাটি হ'ল লুপের প্রতিটি পুনরাবৃত্তিতে একটি নতুন ফাংশন অবজেক্ট তৈরি করার ব্যয় এবং আপনি কোনও বেনাম ফাংশন ব্যবহার করেন না তা নয়:

for (var i = 0; i < 1000; ++i) {    
    myObjects[i].onMyEvent = function() {
        // do something    
    };
}

কোডের একই বডি থাকা এবং লেজিকাল স্কোপ ( বন্ধ হওয়া ) এর কোনও বাধ্যবাধকতা না থাকলেও আপনি হাজার হাজার স্বতন্ত্র ফাংশন অবজেক্ট তৈরি করছেন । অন্যদিকে নিম্নলিখিতটি দ্রুত বলে মনে হচ্ছে, কারণ এটি কেবল লুপ জুড়ে অ্যারে উপাদানগুলিতে একই ফাংশন রেফারেন্সটি নির্ধারণ করে :

function myEventHandler() {
    // do something
}

for (var i = 0; i < 1000; ++i) {
    myObjects[i].onMyEvent = myEventHandler;
}

আপনি যদি লুপটি প্রবেশের আগে বেনামে ফাংশন তৈরি করতে চান তবে লুপের ভিতরে থাকা অবস্থায় অ্যারে উপাদানগুলিতে কেবলমাত্র তার জন্য রেফারেন্স অর্পণ করুন, আপনি দেখতে পাবেন যে নামকরণ ফাংশন সংস্করণের সাথে তুলনা করার সময় কোনও কার্যকারিতা বা শব্দার্থগত পার্থক্য নেই:

var handler = function() {
    // do something    
};
for (var i = 0; i < 1000; ++i) {    
    myObjects[i].onMyEvent = handler;
}

সংক্ষেপে, বেনামে ওভার নামকৃত ফাংশনগুলি ব্যবহার করার জন্য কোনও পর্যবেক্ষণযোগ্য পারফরম্যান্স ব্যয় নেই।

একদিকে যেমন এটি উপরে থেকে প্রদর্শিত হতে পারে যে এর মধ্যে কোনও পার্থক্য নেই:

function myEventHandler() { /* ... */ }

এবং:

var myEventHandler = function() { /* ... */ }

পূর্ববর্তীটি একটি ফাংশন ডিক্লেয়ারেশন যেখানে দ্বিতীয়টি বেনামে ফাংশনে পরিবর্তনশীল অ্যাসাইনমেন্ট। যদিও তাদের একই প্রভাব রয়েছে বলে মনে হতে পারে তবে জাভাস্ক্রিপ্ট তাদের কিছুটা আলাদা আচরণ করে। পার্থক্যটি বোঝার জন্য, আমি " জাভাস্ক্রিপ্ট ফাংশন ঘোষণার অস্পষ্টতা " পড়ার পরামর্শ দিই ।

যেকোন পদ্ধতির জন্য প্রকৃত মৃত্যুর সময়টি মূলত ব্রাউজারের সংকলক এবং রানটাইমের প্রয়োগ দ্বারা নির্ধারিত হয়। আধুনিক ব্রাউজারের পারফরম্যান্সের সম্পূর্ণ তুলনা করার জন্য , জেএস পারফেক্ট সাইটটি দেখুন


আপনি ফাংশন বডিটির আগে বন্ধনীগুলি ভুলে গেছেন। আমি কেবল এটি পরীক্ষা করেছি, তাদের প্রয়োজন।
চিনটো ভোক্রো

মনে হচ্ছে বেঞ্চমার্কের ফলাফলগুলি খুব জেস-ইঞ্জিন নির্ভর!
aleclofabbro

4
জেএস পারফ্টের কোনও ত্রুটি নেই কি: কেস 1 কেবলমাত্র ফাংশনটি সংজ্ঞায়িত করে, যেখানে কেস 2 এবং 3 দুর্ঘটনাক্রমে ফাংশনটিকে কল করে।
bluenote10

সুতরাং এই যুক্তিটি ব্যবহার করে, এর অর্থ কি এই যে node.jsওয়েব অ্যাপ্লিকেশনগুলি বিকাশ করার সময়, অনুরোধ প্রবাহের বাইরে ফাংশনগুলি তৈরি করা এবং বেনামে কলব্যাকগুলি তৈরি করার চেয়ে সেগুলি কলব্যাক হিসাবে পাস করা ভাল?
জাভিয়ার টি মুকোডি

23

আমার পরীক্ষার কোডটি এখানে:

var dummyVar;
function test1() {
    for (var i = 0; i < 1000000; ++i) {
        dummyVar = myFunc;
    }
}

function test2() {
    for (var i = 0; i < 1000000; ++i) {
        dummyVar = function() {
            var x = 0;
            x++;
        };
    }
}

function myFunc() {
    var x = 0;
    x++;
}

document.onclick = function() {
    var start = new Date();
    test1();
    var mid = new Date();
    test2();
    var end = new Date();
    alert ("Test 1: " + (mid - start) + "\n Test 2: " + (end - mid));
}

ফলাফল:
টেস্ট 1: 142ms পরীক্ষা 2: 1983ms

দেখা যাচ্ছে যে জেএস ইঞ্জিনটি টেস্ট 2-তে একই ফাংশনটি সনাক্ত করতে পারে না এবং প্রতিবার এটি সংকলন করে।


4
এই পরীক্ষাটি কোন ব্রাউজারে পরিচালিত হয়েছিল?
andynil

4
আমার জন্য ক্রোম 23: (2ms / 17ms), IE9: (20ms / 83ms), এফএফ 17: (2 মিম / 96 মিমি)
ডেভি 8 ই

আপনার উত্তরটি আরও ওজনের দাবিদার। ইন্টেল i5 4570S এ আমার সময়: ক্রোম 41 (1/9), আইই 11 (1/25), এফএফ 36 (1/14)। স্পষ্টত একটি লুপে বেনাম ফাংশন আরও খারাপ সম্পাদন করে।
ক্লার্ক

4
এই পরীক্ষাটি যতটা কার্যকর হয় তেমন কার্যকর নয়। উভয় উদাহরণে অভ্যন্তরীণ ফাংশনটি আসলে কার্যকর হয়। কার্যকরভাবে এই সমস্ত পরীক্ষাটি দেখায় যে 10000000 বার একটি ফাংশন তৈরি করা একবার একবারে ফাংশন তৈরি করার চেয়ে দ্রুত হয়।
নিউক্লিওন

2

একটি সাধারণ নকশার নীতি হিসাবে, আপনি একই কোডটি একাধিকবার প্রয়োগ করা এড়ানো উচিত। পরিবর্তে আপনার কোনও ফাংশনে সাধারণ কোডটি তুলে নেওয়া উচিত এবং একাধিক জায়গা থেকে এটি (সাধারণ, ভাল পরীক্ষা করা, সংশোধন করা সহজ) ফাংশনটি সম্পাদন করা উচিত।

যদি (আপনি নিজের প্রশ্নটি অনুধাবন করছেন তার বিপরীতে) আপনি একবার অভ্যন্তরীণ ফাংশন ঘোষণা করছেন এবং সেই কোডটি একবার ব্যবহার করছেন (এবং আপনার প্রোগ্রামে অন্য কোনও কিছু নেই) তবে একটি অনিয়ম ফাংশন সম্ভবত (অনুমানের লোকদের দ্বারা) একইরকম আচরণ করা হবে একটি সাধারণ নামকৃত ফাংশন হিসাবে সংকলক।

এটি নির্দিষ্ট দৃষ্টান্তে এটি একটি খুব কার্যকর বৈশিষ্ট্য, তবে অনেক পরিস্থিতিতে ব্যবহার করা উচিত নয়।


1

আমি খুব বেশি পার্থক্য আশা করতে পারব না তবে এটির একটি থাকলে এটি সম্ভবত স্ক্রিপ্টিং ইঞ্জিন বা ব্রাউজার দ্বারা পৃথক হবে।

আপনি কোডটি কুঁচকে ফেলা সহজ মনে করেন, যদি আপনি কয়েক মিলিয়ন বার এই ফাংশনটি কল করার প্রত্যাশা না করেন তবে পারফরম্যান্স একটি বিষয় নয় is


1

যেখানে আমরা পারফরম্যান্সের প্রভাব ফেলতে পারি তা ডিক্লারিং ফাংশনগুলির ক্রিয়াকলাপে। এখানে অন্য কার্যকারিতা বা বাহিরের প্রসঙ্গে ভিতরে ফাংশনগুলি ঘোষণার একটি মানদণ্ড রয়েছে:

http://jsperf.com/function-context-benchmark

ক্রোমে অপারেশনটি দ্রুত হয় যদি আমরা বাইরে ফাংশনটি ঘোষণা করি তবে ফায়ারফক্সে এটি বিপরীত।

অন্য উদাহরণে আমরা দেখতে পাই যে যদি অভ্যন্তরীণ ফাংশনটি খাঁটি ফাংশন না হয় তবে এটির ফায়ারফক্সেও পারফরম্যান্সের ঘাটতি থাকবে : http://jsperf.com/function-context-benchmark-3


0

বিভিন্ন ব্রাউজারগুলি, বিশেষত আইই ব্রাউজারগুলিতে আপনার লুপটি স্পষ্টভাবে কী করে তোলে তা নীচে লুপিং করছে:

for (var i = 0, iLength = imgs.length; i < iLength; i++)
{
   // do something
}

আপনি একটি স্বেচ্ছাসেবী 1000 লুপ অবস্থায় রেখেছেন, কিন্তু আপনি অ্যারে সমস্ত আইটেম যেতে চাইলে আপনি আমার ড্রিফট পাবেন।


0

একটি রেফারেন্স প্রায় সবসময় ধীর হতে চলেছে তবে জিনিসটি যার প্রতি তা উল্লেখ করছে। এটিকে এভাবে ভাবুন - আসুন আমরা বলি যে আপনি 1 + 1 যোগ করার ফলাফলটি মুদ্রণ করতে চান যা আরও অর্থবোধ করে:

alert(1 + 1);

বা

a = 1;
b = 1;
alert(a + b);

আমি বুঝতে পারি যে এটি দেখার এক সহজ সরল উপায় তবে এটি উদাহরণস্বরূপ, তাই না? কোনও রেফারেন্সটি কেবলমাত্র একাধিকবার ব্যবহার হতে চলেছে তা ব্যবহার করুন - উদাহরণস্বরূপ, এই উদাহরণগুলির মধ্যে কোনটি আরও বেশি অর্থবোধ করে:

$(a.button1).click(function(){alert('you clicked ' + this);});
$(a.button2).click(function(){alert('you clicked ' + this);});

বা

function buttonClickHandler(){alert('you clicked ' + this);}
$(a.button1).click(buttonClickHandler);
$(a.button2).click(buttonClickHandler);

দ্বিতীয়টি হ'ল আরও ভাল অনুশীলন, যদিও এটি আরও লাইন পেয়েছে। আশা করি এই সমস্ত সহায়ক। (এবং জ্যাকোরি সিনট্যাক্স কাউকে ছাড়েনি)


0

@ নিকফ

(আশা করি আমার কাছে কেবল মন্তব্য করার জবাবটি ছিল তবে আমি কেবল এই সাইটটি পেয়েছি)

আমার বক্তব্যটি হ'ল এখানে নামকরণ / বেনামে ফাংশন এবং একটি পুনরাবৃত্তিতে সম্পাদন + সংকলনের ব্যবহারের ক্ষেত্রে বিভ্রান্তি রয়েছে। যেমন আমি চিত্রিত করেছি, আনয়ন + নামের পার্থক্যটি নিজের কাছে নগণ্য - আমি বলছি এটি ব্যবহারের ক্ষেত্রে ত্রুটিযুক্ত।

এটি আমার কাছে সুস্পষ্ট বলে মনে হয় তবে আমি যদি মনে করি না তবে সেরা পরামর্শটি হ'ল "বোবা জিনিসগুলি করবেন না" (যার মধ্যে ধ্রুব ব্লক শিফটিং + এই ব্যবহারের ক্ষেত্রে অবজেক্ট তৈরি করা এক) এবং যদি আপনি নিশ্চিত না হন তবে পরীক্ষা করুন!


0

হ্যাঁ! বেনামে ফাংশনগুলি নিয়মিত ফাংশনের চেয়ে দ্রুত হয়। সম্ভবত যদি গতিটির সর্বোচ্চ গুরুত্ব থাকে ... কোড পুনরায় ব্যবহারের চেয়ে গুরুত্বপূর্ণ তবে বেনাম ফাংশনগুলি ব্যবহার করে বিবেচনা করুন।

জাভাস্ক্রিপ্ট এবং বেনাম ফাংশনগুলি অনুকূলকরণ সম্পর্কে সত্যিই একটি ভাল নিবন্ধ আছে:

http://dev.opera.com/articles/view/efficient-javascript/?page=2


0

নামবিহীন বস্তুর চেয়ে বেনামে অবজেক্টগুলি দ্রুত। তবে আরও ফাংশনগুলিতে কল করা আরও ব্যয়বহুল, এবং এমন একটি ডিগ্রি যা বেনাম ফাংশন ব্যবহার করে আপনি পেতে পারেন কোনও সঞ্চয়কে গ্রহন করে। বলা প্রতিটি ফাংশন কল স্ট্যাককে যুক্ত করে, যা একটি ছোট কিন্তু অ-তুচ্ছ পরিমাণের ওভারহেডের সাথে পরিচিত করে।

তবে আপনি এনক্রিপশন / ডিক্রিপশন রুটিন বা পারফরম্যান্সের সাথে অনুরূপ সংবেদনশীল কিছু না লিখলে অন্য অনেকে উল্লেখ করেছেন যে দ্রুত কোডের দ্বারা মার্জিত, সহজেই পঠনযোগ্য কোডের জন্য অপ্টিমাইজ করা ভাল।

ধরে নিই যে আপনি ভাল-আর্কিটেটেড কোড লিখছেন, তারপরে গতির সমস্যাগুলি তাদের দোভাষী / সংকলক লেখার দায়িত্ব হওয়া উচিত।


0

@ নিকফ

এটি একটি বরং চর্বিযুক্ত পরীক্ষা, আপনি মৃত্যুর সাথে তুলনা করছেন সেখানে ও সংকলনের যা স্পষ্টতই পদ্ধতি 2 (একটি বার সংকলন করে) এর সাথে পদ্ধতি 1 (সংকলন এন টাইম, জেএস ইঞ্জিন নির্ভর করে) ব্যয় করছে। আমি কোনও জেএস বিকাশকারী কল্পনা করতে পারি না যারা তাদের প্রবেশন রাইটিং কোডটি এমনভাবে পাস করবেন।

আরও বেশি বাস্তবসম্মত দৃষ্টিভঙ্গি হ'ল অনামী দায়িত্ব, যেমন আপনি নিজের নথির জন্য ব্যবহার করছেন on অনিক্লিক পদ্ধতিটি নীচের মতো, যা বাস্তবে মৃদুভাবে আনোন পদ্ধতির পক্ষে।

আপনার অনুরূপ পরীক্ষার কাঠামো ব্যবহার করে:


function test(m)
{
    for (var i = 0; i < 1000000; ++i) 
    {
        m();
    }
}

function named() {var x = 0; x++;}

var test1 = named;

var test2 = function() {var x = 0; x++;}

document.onclick = function() {
    var start = new Date();
    test(test1);
    var mid = new Date();
    test(test2);
    var end = new Date();
    alert ("Test 1: " + (mid - start) + "ms\n Test 2: " + (end - mid) + "ms");
}

0

@ নিকফের মন্তব্যে যেমন উল্লেখ করা হয়েছে: উত্তর

একটি মিলিয়ন বার তৈরির চেয়ে একবারে একটি ক্রিয়াকলাপ তৈরি করছে

হ্যাঁ হ্যাঁ তবে তার জেএস পারফেক্ট হিসাবে, এটি মিলিয়ন ফ্যাক্টর দ্বারা ধীর নয়, এটি দেখায় যে এটি সময়ের সাথে আসলে দ্রুত হয়।

আমার কাছে আরও আকর্ষণীয় প্রশ্ন হ'ল:

একবারে পুনরাবৃত্তি তৈরি করতে + রান একবার তুলনা করে কীভাবে একবার + পুনরাবৃত্তি চালানো হয়

যদি কোনও ফাংশন একটি জটিল গণনা সম্পাদন করে তবে ফাংশন অবজেক্ট তৈরির সময়টি সম্ভবত খুব নগন্য। তবে রান দ্রুত হয় এমন ক্ষেত্রে ওভার হেডের তৈরি সম্পর্কে কী বলা যায় ? এই ক্ষেত্রে:

// Variant 1: create once
function adder(a, b) {
  return a + b;
}
for (var i = 0; i < 100000; ++i) {
  var x = adder(412, 123);
}

// Variant 2: repeated creation via function statement
for (var i = 0; i < 100000; ++i) {
  function adder(a, b) {
    return a + b;
  }
  var x = adder(412, 123);
}

// Variant 3: repeated creation via function expression
for (var i = 0; i < 100000; ++i) {
  var x = (function(a, b) { return a + b; })(412, 123);
}

এই জেএস পারফেক্ট দেখায় যে একবারে ফাংশন তৈরি করা প্রত্যাশার চেয়ে দ্রুত হয়। তবে, সাধারণ অ্যাডের মতো খুব দ্রুত অপারেশন করেও বারবার ফাংশনটি তৈরির ওভারহেড কেবল কয়েক শতাংশ।

পার্থক্যটি কেবল তখনই তাত্পর্যপূর্ণ হয়ে ওঠে যেখানে ফাংশন অবজেক্ট তৈরি করা জটিল, তুচ্ছ রান সময়কে বজায় রাখার সময়, যেমন, যদি পুরো ফাংশন বডিটি একটিতে আবৃত থাকে if (unlikelyCondition) { ... }

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.