เมื่อเทียบกับ C/C ++ การประมวลผลของ JavaScript ในหน่วยความจำใน JavaScript ที่เราใช้ทำให้เราให้ความสำคัญกับการเขียนตรรกะทางธุรกิจในการพัฒนา อย่างไรก็ตามด้วยความซับซ้อนอย่างต่อเนื่องของธุรกิจการพัฒนาแอปพลิเคชันหน้าเดียวแอปพลิเคชัน HTML5 มือถือโปรแกรม Node.js ฯลฯ ความล่าช้าและการล้นหน่วยความจำที่เกิดจากปัญหาหน่วยความจำใน JavaScript ไม่คุ้นเคยอีกต่อไป
บทความนี้จะหารือเกี่ยวกับการใช้หน่วยความจำและการเพิ่มประสิทธิภาพจากระดับภาษาของ JavaScript จากแง่มุมที่ทุกคนคุ้นเคยหรือได้ยินเล็กน้อยไปจนถึงสิ่งที่ทุกคนจะไม่สังเกตเห็นส่วนใหญ่เราจะวิเคราะห์พวกเขาทีละคน
1. การจัดการหน่วยความจำระดับภาษา
1.1 ขอบเขต
ขอบเขตเป็นกลไกการทำงานที่สำคัญมากในการเขียนโปรแกรม JavaScript มันไม่ได้ดึงดูดความสนใจของผู้เริ่มต้นในการเขียนโปรแกรม JavaScript แบบซิงโครนัส แต่ในการเขียนโปรแกรมแบบอะซิงโครนัสทักษะการควบคุมขอบเขตที่ดีได้กลายเป็นทักษะที่จำเป็นสำหรับนักพัฒนาจาวาสคริปต์ นอกจากนี้ขอบเขตมีบทบาทสำคัญในการจัดการหน่วยความจำ JavaScript
ใน JavaScript สามารถเรียกใช้ฟังก์ชั่นพร้อมข้อความและขอบเขตทั่วโลกที่สามารถกำหนดขอบเขตได้
ดังที่แสดงในรหัสต่อไปนี้เป็นตัวอย่าง:
การคัดลอกรหัสมีดังนี้:
var foo = function () {
var local = {};
-
foo ();
console.log (ท้องถิ่น); // => ไม่ได้กำหนด
var bar = function () {
local = {};
-
บาร์();
console.log (ท้องถิ่น); -
ที่นี่เรากำหนดฟังก์ชั่น foo () และฟังก์ชั่น bar () ความตั้งใจของพวกเขาคือการกำหนดตัวแปรชื่อท้องถิ่น แต่ผลลัพธ์สุดท้ายนั้นแตกต่างอย่างสิ้นเชิง
ในฟังก์ชั่น FOO () เราใช้คำสั่ง VAR เพื่อประกาศว่าตัวแปรท้องถิ่นถูกกำหนดไว้ เนื่องจากขอบเขตถูกสร้างขึ้นภายในร่างกายฟังก์ชั่นตัวแปรนี้ถูกกำหนดไว้ในขอบเขต ยิ่งไปกว่านั้นไม่มีการประมวลผลส่วนขยายขอบเขตในฟังก์ชัน foo () ดังนั้นหลังจากการดำเนินการฟังก์ชันตัวแปรท้องถิ่นจะถูกทำลายเช่นกัน อย่างไรก็ตามตัวแปรนี้ไม่สามารถเข้าถึงได้ในขอบเขตด้านนอก
ในฟังก์ชั่นบาร์ () ตัวแปรโลคัลไม่ได้ถูกประกาศโดยใช้คำสั่ง VAR แต่แทนที่จะกำหนดโดยตรงเป็นตัวแปรทั่วโลก ดังนั้นตัวแปรนี้สามารถเข้าถึงได้โดยขอบเขตด้านนอก
การคัดลอกรหัสมีดังนี้:
local = {};
// คำจำกัดความที่นี่เทียบเท่ากับ
global.local = {};
1.2 โซ่ขอบเขต
ในการเขียนโปรแกรม JavaScript คุณจะได้พบกับฟังก์ชั่นการทำรังแบบหลายชั้นซึ่งเป็นตัวแทนทั่วไปของโซ่ขอบเขต
ดังที่แสดงในรหัสต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น foo () {
var val = 'สวัสดี';
แถบฟังก์ชัน () {
ฟังก์ชั่น baz () {
Global.val = 'World;'
-
baz ();
console.log (val); // => สวัสดี
-
บาร์();
-
foo ();
จากคำอธิบายก่อนหน้าเกี่ยวกับขอบเขตคุณอาจคิดว่าผลลัพธ์ที่แสดงในรหัสที่นี่คือโลก แต่ผลลัพธ์ที่แท้จริงคือสวัสดี ผู้เริ่มต้นหลายคนจะเริ่มรู้สึกสับสนที่นี่ดังนั้นลองมาดูกันว่ารหัสนี้ทำงานอย่างไร
ตั้งแต่ JavaScript การค้นหาตัวระบุตัวแปรเริ่มต้นจากขอบเขตปัจจุบันและมองออกไปข้างนอกจนกระทั่งขอบเขตทั่วโลก ดังนั้นการเข้าถึงตัวแปรในรหัส JavaScript สามารถดำเนินการได้ออกไปข้างนอกเท่านั้น แต่ไม่ได้ย้อนกลับ
การดำเนินการของฟังก์ชั่น BAZ () กำหนด VAL ตัวแปรทั่วโลกในขอบเขตทั่วโลก ในฟังก์ชั่นแท่ง () เมื่อเข้าถึงตัวระบุ Val หลักการของการค้นหาจากด้านในไปด้านนอกคือ: หากไม่พบในขอบเขตของฟังก์ชันแท่งมันจะไปที่เลเยอร์ก่อนหน้านั่นคือขอบเขตของฟังก์ชัน foo ()
อย่างไรก็ตามกุญแจสำคัญในการทำให้ทุกคนสับสนคือ: การเข้าถึงตัวระบุนี้พบตัวแปรที่ตรงกันในขอบเขตของฟังก์ชั่น FOO () และจะไม่มองออกไปข้างนอกดังนั้น Val ตัวแปรทั่วโลกที่กำหนดไว้ในฟังก์ชัน BAZ () ไม่มีผลในการเข้าถึงตัวแปรนี้
1.3 ปิด
เรารู้ว่าการค้นหาตัวระบุใน JavaScript เป็นไปตามหลักการของการออกไปข้างใน อย่างไรก็ตามด้วยความซับซ้อนของตรรกะทางธุรกิจคำสั่งจัดส่งเพียงครั้งเดียวยังห่างไกลจากการตอบสนองความต้องการใหม่ที่เพิ่มขึ้น
มาดูรหัสต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น foo () {
var local = 'hello';
return function () {
กลับท้องถิ่น;
-
-
var bar = foo ();
console.log (bar ()); // => สวัสดี
เทคโนโลยีที่อนุญาตให้ขอบเขตด้านนอกเข้าถึงขอบเขตภายในดังที่แสดงไว้ที่นี่คือการปิด ด้วยแอปพลิเคชันของฟังก์ชั่นการสั่งซื้อที่สูงขึ้นขอบเขตของฟังก์ชั่น foo () คือ "ขยาย"
ฟังก์ชั่น foo () ส่งคืนฟังก์ชันที่ไม่ระบุชื่อซึ่งมีอยู่ภายในขอบเขตของฟังก์ชัน foo () เพื่อให้คุณสามารถเข้าถึงตัวแปรท้องถิ่นภายในขอบเขตของฟังก์ชัน Foo () และบันทึกการอ้างอิง เนื่องจากฟังก์ชั่นนี้ส่งคืนตัวแปรโลคัลโดยตรงฟังก์ชัน BAR () สามารถดำเนินการโดยตรงในขอบเขตด้านนอกเพื่อรับตัวแปรท้องถิ่น
การปิดเป็นคุณสมบัติระดับสูงของ JavaScript และเราสามารถใช้เพื่อให้ได้เอฟเฟกต์ที่ซับซ้อนมากขึ้นเพื่อตอบสนองความต้องการที่แตกต่างกัน อย่างไรก็ตามควรสังเกตว่าเนื่องจากฟังก์ชั่นที่มีการอ้างอิงตัวแปรภายในถูกนำออกมาจากฟังก์ชั่นตัวแปรในขอบเขตนี้จะไม่ถูกทำลายหลังจากฟังก์ชั่นถูกดำเนินการจนกว่าจะมีการอ้างอิงตัวแปรภายในทั้งหมด ดังนั้นการประยุกต์ใช้การปิดสามารถทำให้หน่วยความจำไม่ฟรี
2. กลไกการรีไซเคิลหน่วยความจำของ JavaScript
ที่นี่ฉันจะใช้เครื่องยนต์ V8 ที่ใช้โดย Chrome และ Node.js และเปิดตัวโดย Google เป็นตัวอย่างเพื่อแนะนำกลไกการรีไซเคิลหน่วยความจำของ JavaScript โดยย่อ สำหรับเนื้อหาที่มีรายละเอียดเพิ่มเติมคุณสามารถซื้อหนังสือของเพื่อนที่ดีของฉัน Ling Ling "เชิงลึกและเข้าใจง่าย node.js" สำหรับการเรียนรู้ซึ่งเป็นการแนะนำรายละเอียดในบท "การควบคุมหน่วยความจำ"
ใน V8 วัตถุ JavaScript ทั้งหมดจะถูกจัดสรรผ่าน "heap"
เมื่อเราประกาศและกำหนดค่าในรหัส V8 จะจัดสรรส่วนหนึ่งของตัวแปรนี้ในหน่วยความจำฮีป หากหน่วยความจำที่ร้องขอไม่เพียงพอในการจัดเก็บตัวแปรนี้ V8 จะใช้งานหน่วยความจำต่อไปจนกว่าขนาดของฮีปจะถึงขีด จำกัด ของหน่วยความจำที่ V8 โดยค่าเริ่มต้นขีด จำกัด สูงสุดของหน่วยความจำ HEAP ของ V8 คือ 1464MB สำหรับระบบ 64 บิตและ 732MB ในระบบ 32 บิตซึ่งประมาณ 1.4GB และ 0.7GB
นอกจากนี้ V8 ยังจัดการวัตถุ JavaScript ในหน่วยความจำกองในรุ่น: รุ่นใหม่และรุ่นเก่า รุ่นใหม่คือวัตถุ JavaScript ที่มีวงจรการอยู่รอดสั้น ๆ เช่นตัวแปรชั่วคราว, สตริง, ฯลฯ ; ในขณะที่รุ่นเก่าเป็นวัตถุที่มีรอบการอยู่รอดยาวหลังจากคอลเลกชันขยะหลายรายการเช่นตัวควบคุมหลักวัตถุเซิร์ฟเวอร์ ฯลฯ
อัลกอริทึมการรีไซเคิลขยะเป็นส่วนสำคัญของการพัฒนาภาษาการเขียนโปรแกรมและอัลกอริทึมการรีไซเคิลขยะที่ใช้ใน V8 เป็นส่วนใหญ่ดังนี้:
1. อัลกอริทึม Scavange: การจัดการพื้นที่หน่วยความจำดำเนินการผ่านการคัดลอกส่วนใหญ่ใช้ในพื้นที่หน่วยความจำของรุ่นใหม่;
2. อัลกอริทึมการกวาดมาร์คและอัลกอริธึมขนาดกะทัดรัด: หน่วยความจำกองถูกจัดเรียงและรีไซเคิลผ่านการทำเครื่องหมายส่วนใหญ่ใช้สำหรับการตรวจสอบและรีไซเคิลวัตถุรุ่นเก่า
PS: การใช้งานการเก็บรวบรวมขยะ V8 โดยละเอียดเพิ่มเติมสามารถเรียนรู้ได้โดยการอ่านหนังสือเอกสารและซอร์สโค้ดที่เกี่ยวข้อง
ลองมาดูกันว่าเครื่องยนต์ JavaScript จะรีไซเคิลวัตถุอะไร
2.1 ขอบเขตและการอ้างอิง
ผู้เริ่มต้นมักจะเชื่อผิด ๆ ว่าเมื่อมีการดำเนินการฟังก์ชั่นวัตถุที่ประกาศไว้ในฟังก์ชั่นจะถูกทำลาย แต่ในความเป็นจริงความเข้าใจนี้ไม่ได้เข้มงวดและครอบคลุมและเป็นเรื่องง่ายที่จะสับสน
การอ้างอิงเป็นกลไกที่สำคัญมากในการเขียนโปรแกรม JavaScript แต่น่าแปลกที่นักพัฒนาส่วนใหญ่จะไม่ให้ความสนใจกับมันหรือแม้แต่เข้าใจ การอ้างอิงหมายถึงความสัมพันธ์เชิงนามธรรม "การเข้าถึงรหัสกับวัตถุ" มันค่อนข้างคล้ายกับพอยน์เตอร์ C/C ++ แต่ไม่ใช่สิ่งเดียวกัน การอ้างอิงยังเป็นกลไกที่สำคัญที่สุดของเครื่องยนต์จาวาสคริปต์ในการรวบรวมขยะ
รหัสต่อไปนี้เป็นตัวอย่าง:
การคัดลอกรหัสมีดังนี้:
-
var val = 'Hello World';
ฟังก์ชั่น foo () {
return function () {
กลับมาวาล;
-
-
global.bar = foo ();
-
หลังจากอ่านรหัสนี้คุณสามารถบอกได้ว่าวัตถุใดที่ยังคงอยู่รอดหลังจากดำเนินการส่วนหนึ่งของรหัสนี้หรือไม่?
ตามหลักการที่เกี่ยวข้องวัตถุที่ไม่ได้รีไซเคิลและปล่อยออกมาในรหัสนี้รวมถึง Val และ Bar () อะไรทำให้พวกเขาไม่สามารถรีไซเคิลได้?
เครื่องยนต์ JavaScript ทำการรวบรวมขยะได้อย่างไร? อัลกอริทึมการรวบรวมขยะที่กล่าวถึงข้างต้นใช้ในระหว่างการรีไซเคิลเท่านั้น ดังนั้นมันจะรู้ได้อย่างไรว่าวัตถุใดที่สามารถรีไซเคิลได้และวัตถุใดที่จำเป็นต้องอยู่รอดต่อไป? คำตอบคือการอ้างอิงถึงวัตถุ JavaScript
ในรหัส JavaScript แม้ว่าคุณเพียงแค่เขียนชื่อตัวแปรเป็นบรรทัดเดียวโดยไม่ต้องทำอะไรเลยเครื่องมือ JavaScript จะคิดว่านี่เป็นพฤติกรรมการเข้าถึงของวัตถุและมีการอ้างอิงถึงวัตถุ เพื่อให้แน่ใจว่าพฤติกรรมการรวบรวมขยะจะไม่ส่งผลกระทบต่อการทำงานของตรรกะของโปรแกรมเครื่องยนต์ JavaScript จะต้องไม่รีไซเคิลวัตถุที่ใช้งานมิฉะนั้นจะยุ่ง ดังนั้นมาตรฐานสำหรับการตัดสินว่าวัตถุมีการใช้งานหรือไม่นั้นยังคงมีการอ้างอิงถึงวัตถุ แต่ในความเป็นจริงนี่เป็นการประนีประนอมเนื่องจากการอ้างอิง JavaScript สามารถถ่ายโอนได้ดังนั้นอาจมีการอ้างอิงบางอย่างที่นำไปสู่ขอบเขตทั่วโลก แต่ในความเป็นจริงมันไม่จำเป็นที่จะต้องเข้าถึงพวกเขาในตรรกะทางธุรกิจอีกต่อไป
วิธีการใช้ตัวแปรและการอ้างอิงในท่าทางที่ถูกต้องเป็นกุญแจสำคัญในการเพิ่มประสิทธิภาพ JavaScript จากระดับภาษา
3. เพิ่มประสิทธิภาพ JavaScript ของคุณ
ในที่สุดก็มาถึงจุด ขอบคุณมากที่ได้เห็นสิ่งนี้ด้วยความอดทน หลังจากการแนะนำมากมายข้างต้นฉันเชื่อว่าคุณมีความเข้าใจที่ดีเกี่ยวกับกลไกการจัดการหน่วยความจำของ JavaScript จากนั้นทักษะต่อไปนี้จะทำให้คุณรู้สึกดีขึ้น
3.1 ใช้ประโยชน์จากฟังก์ชั่นที่ดี
หากคุณมีนิสัยในการอ่านโครงการ JavaScript ที่ยอดเยี่ยมคุณจะพบว่าเมื่อพัฒนารหัส JavaScript ส่วนหน้าคนใหญ่หลายคนมักจะใช้ฟังก์ชั่นที่ไม่ระบุชื่อเพื่อห่อมันไว้ที่ชั้นนอกสุดของรหัส
การคัดลอกรหัสมีดังนี้:
(การทำงาน() {
// รหัสธุรกิจหลัก
-
บางคนมีความก้าวหน้ามากขึ้น:
การคัดลอกรหัสมีดังนี้:
; (ฟังก์ชั่น (win, doc, $, undefined) {
// รหัสธุรกิจหลัก
}) (หน้าต่าง, เอกสาร, jQuery);
แม้แต่โซลูชันการโหลดแบบโมดูลาร์ส่วนหน้าเช่น requirejs, SEAJs, OZJs ฯลฯ ทั้งหมดใช้รูปแบบที่คล้ายกัน:
การคัดลอกรหัสมีดังนี้:
// requirejs
กำหนด (['jQuery'], ฟังก์ชั่น ($) {
// รหัสธุรกิจหลัก
-
// seajs
กำหนด ('โมดูล', ['dep', 'Underscore'], ฟังก์ชั่น ($, _) {
// รหัสธุรกิจหลัก
-
หากคุณบอกว่ารหัสโอเพ่นซอร์สของ Node.js จำนวนมากไม่ได้ประมวลผลด้วยวิธีนี้คุณก็ผิด ก่อนที่จะเรียกใช้รหัสจริง Node.js จะห่อไฟล์. js แต่ละไฟล์ลงในแบบฟอร์มต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
(ฟังก์ชั่น (การส่งออก, ต้องการ, โมดูล, __dirname, __filename) {
// รหัสธุรกิจหลัก
-
ประโยชน์ของการทำสิ่งนี้คืออะไร? เราทุกคนรู้ว่าในตอนต้นของบทความเราบอกว่า JavaScript สามารถมีฟังก์ชั่นที่กำหนดขอบเขตพร้อมข้อความและขอบเขตทั่วโลก นอกจากนี้เรายังรู้ว่าวัตถุที่กำหนดไว้ในขอบเขตทั่วโลกอาจอยู่รอดได้จนกว่ากระบวนการจะออก หากเป็นวัตถุขนาดใหญ่มันจะลำบาก ตัวอย่างเช่นบางคนชอบแสดงเทมเพลตใน JavaScript:
การคัดลอกรหัสมีดังนี้:
<? php
$ db = mysqli_connect (เซิร์ฟเวอร์, ผู้ใช้, รหัสผ่าน, 'myApp');
$ topics = mysqli_query ($ db, "เลือก * จากหัวข้อ;");
-
<! doctype html>
<html lang = "en">
<head>
<meta charset = "utf-8">
<title> คุณเป็นคนตลกที่ได้รับเชิญจากลิงหรือไม่? </title>
</head>
<body>
<ul id = "หัวข้อ"> </ul>
<script type = "text/tmpl" id = "topic-tmpl">
<li>
<H1> <%= title%> </h1>
<p> <%= เนื้อหา%> </p>
</li>
</script>
<script type = "text/javascript">
var data = <? php echo json_encode ($ topics); -
var topictmpl = document.querySelector ('#topic-tmpl'). innerhtml;
var render = function (tmlp, view) {
var compiled = tmlp
.replace (// n/g, '// n')
.replace (/<%= ([/s/s]+?)%>/g, ฟังก์ชัน (จับคู่, รหัส) {
return '" + escape (' + code + ') +"';
-
รวบรวม = [
'var res = "";',
'ด้วย (ดู || {}) {',
'res = "' + คอมไพล์ + '";',
-
'Return Res;'
] .oin ('/n');
var fn = ฟังก์ชั่นใหม่ ('ดู', รวบรวม);
ส่งคืน fn (ดู);
-
var topics = document.querySelector ('#หัวข้อ');
ฟังก์ชั่น init ()
data.foreach (ฟังก์ชั่น (หัวข้อ) {
Topics.innerhtml += render (topictmpl, หัวข้อ);
-
-
init ();
</script>
</body>
</html>
รหัสประเภทนี้มักจะเห็นได้ในผลงานของสามเณร ปัญหาที่นี่คืออะไร? หากจำนวนข้อมูลที่ได้จากฐานข้อมูลมีขนาดใหญ่มากตัวแปรข้อมูลจะไม่ได้ใช้งานหลังจากที่ส่วนหน้าเสร็จสิ้นการเรนเดอร์เทมเพลต อย่างไรก็ตามเนื่องจากตัวแปรนี้ถูกกำหนดไว้ในขอบเขตทั่วโลกเอ็นจิ้น JavaScript จะไม่รีไซเคิลและทำลายมัน สิ่งนี้จะยังคงอยู่ในหน่วยความจำกองรุ่นเก่าจนกว่าหน้าจะปิด
แต่ถ้าเราทำการดัดแปลงอย่างง่าย ๆ และห่อเลเยอร์ของฟังก์ชั่นนอกรหัสโลจิคัลเอฟเฟกต์จะแตกต่างกันมาก หลังจากการเรนเดอร์ UI เสร็จสมบูรณ์การอ้างอิงของรหัสไปยังข้อมูลจะถูกยกเลิกเช่นกัน เมื่อมีการดำเนินการฟังก์ชั่นนอกสุดแล้วเอ็นจิ้น JavaScript จะเริ่มตรวจสอบวัตถุในนั้นและสามารถรีไซเคิลข้อมูลได้
3.2 อย่ากำหนดตัวแปรทั่วโลก
เราเพิ่งพูดถึงเรื่องนั้นเมื่อตัวแปรถูกกำหนดไว้ในขอบเขตทั่วโลกเครื่องยนต์ JavaScript จะไม่รีไซเคิลและทำลายมันโดยค่าเริ่มต้น สิ่งนี้จะยังคงอยู่ในหน่วยความจำกองรุ่นเก่าจนกว่าหน้าจะปิด
จากนั้นเราได้ปฏิบัติตามหลักการเสมอ: อย่าใช้ตัวแปรทั่วโลก แม้ว่าตัวแปรระดับโลกจะพัฒนาได้ง่ายมาก แต่ปัญหาที่เกิดจากตัวแปรระดับโลกนั้นร้ายแรงกว่าความสะดวกสบายที่เกิดขึ้น
ทำให้ตัวแปรมีโอกาสน้อยที่จะรีไซเคิล
1. ความสับสนเกิดขึ้นได้อย่างง่ายดายเมื่อหลายคนทำงานร่วมกัน
2. มันง่ายที่จะแทรกแซงในห่วงโซ่ขอบเขต
3. ร่วมกับฟังก์ชั่นการห่อด้านบนเรายังสามารถจัดการ "ตัวแปรทั่วโลก" ผ่านฟังก์ชั่นการห่อ
3.3 ตัวแปรที่ไม่ได้รับการอ้างอิงด้วยตนเอง
หากไม่จำเป็นต้องใช้ตัวแปรในรหัสธุรกิจตัวแปรสามารถตรวจสอบได้ด้วยตนเองเพื่อให้รีไซเคิล
การคัดลอกรหัสมีดังนี้:
var data = { / * ข้อมูลขนาดใหญ่บางอย่าง * /};
// blah blah blah
data = null;
3.4 ใช้ประโยชน์จากการโทรกลับ
นอกเหนือจากการใช้การปิดสำหรับการเข้าถึงตัวแปรภายในแล้วเรายังสามารถใช้ฟังก์ชั่นการโทรกลับที่เป็นที่นิยมมากในขณะนี้สำหรับการประมวลผลธุรกิจ
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น getData (โทรกลับ) {
var data = 'ข้อมูลขนาดใหญ่บางอย่าง';
การโทรกลับ (null, data);
-
getData (ฟังก์ชั่น (err, data) {
console.log (ข้อมูล);
ฟังก์ชั่นการโทรกลับเป็นเทคโนโลยีของสไตล์การส่งต่อ (CPS) รูปแบบของการเขียนโปรแกรมนี้ถ่ายโอนโฟกัสทางธุรกิจของฟังก์ชั่นจากค่าส่งคืนไปยังฟังก์ชั่นการโทรกลับ และมีประโยชน์มากมายจากการปิด:
1. หากพารามิเตอร์ที่ผ่านเป็นประเภทพื้นฐาน (เช่นสตริงค่าตัวเลข) พารามิเตอร์ที่เป็นทางการที่ผ่านในฟังก์ชันการโทรกลับจะถูกคัดลอกค่าและจะง่ายกว่าที่จะรีไซเคิลหลังจากใช้รหัสธุรกิจ
2. ผ่านการเรียกกลับนอกเหนือจากการร้องขอแบบซิงโครนัสแล้วเรายังสามารถใช้พวกเขาในการเขียนโปรแกรมแบบอะซิงโครนัสซึ่งเป็นสไตล์การเขียนที่ได้รับความนิยมมากในขณะนี้
3. ฟังก์ชั่นการโทรกลับมักเป็นฟังก์ชันที่ไม่ระบุชื่อชั่วคราว เมื่อฟังก์ชั่นการร้องขอถูกดำเนินการแล้วการอ้างอิงถึงฟังก์ชั่นการโทรกลับจะถูกยกเลิกและจะถูกนำกลับมาใช้ใหม่
3.5 การจัดการปิดที่ดี
เมื่อความต้องการทางธุรกิจของเรา (เช่นการเชื่อมโยงเหตุการณ์แบบวงกลมคุณลักษณะส่วนตัวการโทรกลับพร้อมอาร์กิวเมนต์ ฯลฯ ) จะต้องใช้การปิดโปรดระวังรายละเอียด
เหตุการณ์ที่มีผลผูกพันแบบวนรอบอาจกล่าวได้ว่าเป็นหลักสูตรภาคบังคับสำหรับการเริ่มต้นด้วยการปิด JavaScript สมมติว่าสถานการณ์: มีหกปุ่มที่สอดคล้องกับหกเหตุการณ์ เมื่อผู้ใช้คลิกปุ่มเหตุการณ์ที่เกี่ยวข้องจะถูกส่งออกในสถานที่ที่ระบุ
การคัดลอกรหัสมีดังนี้:
var btns = document.querySelectorall ('. btn'); // 6 องค์ประกอบ
var output = document.querySelector ('#output');
เหตุการณ์ var = [1, 2, 3, 4, 5, 6];
// กรณีที่ 1
สำหรับ (var i = 0; i <btns.length; i ++) {
btns [i] .onclick = function (evt) {
output.innerText + = 'คลิก' + เหตุการณ์ [i];
-
-
// กรณีที่ 2
สำหรับ (var i = 0; i <btns.length; i ++) {
btns [i] .onclick = (ฟังก์ชั่น (ดัชนี) {
ฟังก์ชั่น return (evt) {
output.innerText + = 'คลิก' + เหตุการณ์ [ดัชนี];
-
})(ฉัน);
-
// กรณี 3
สำหรับ (var i = 0; i <btns.length; i ++) {
btns [i] .onclick = (ฟังก์ชั่น (เหตุการณ์) {
ฟังก์ชั่น return (evt) {
output.innerText + = 'คลิก' + เหตุการณ์;
-
}) (เหตุการณ์ [i]);
-
วิธีแก้ปัญหาแรกที่นี่เป็นข้อผิดพลาดในเหตุการณ์ที่มีผลผูกพันลูปทั่วไป ฉันจะไม่อธิบายรายละเอียดที่นี่ คุณสามารถอ้างถึงคำตอบของฉันในรายละเอียดของชาวเน็ต ความแตกต่างระหว่างการแก้ปัญหาที่สองและสามอยู่ในพารามิเตอร์ที่ผ่านในการปิด
พารามิเตอร์ที่ส่งผ่านในรูปแบบที่สองคือตัวห้อยลูปปัจจุบันในขณะที่หลังจะถูกส่งผ่านโดยตรงไปยังวัตถุเหตุการณ์ที่เกี่ยวข้อง ในความเป็นจริงหลังเหมาะสำหรับแอปพลิเคชันข้อมูลจำนวนมากเนื่องจากในการเขียนโปรแกรมฟังก์ชั่น JavaScript พารามิเตอร์ที่ส่งผ่านในการเรียกใช้ฟังก์ชันเป็นวัตถุประเภทพื้นฐานดังนั้นพารามิเตอร์ที่เป็นทางการที่ได้รับในร่างกายฟังก์ชันจะเป็นค่าสำเนา หลังจากการเชื่อมโยงเหตุการณ์เสร็จสิ้นตัวแปรเหตุการณ์สามารถเรียกใช้งานด้วยตนเองเพื่อลดการใช้หน่วยความจำในขอบเขตด้านนอก ยิ่งไปกว่านั้นเมื่อองค์ประกอบถูกลบฟังก์ชั่นการฟังเหตุการณ์ที่สอดคล้องกันวัตถุเหตุการณ์และฟังก์ชั่นการปิดจะถูกทำลายและรีไซเคิล
3.6 หน่วยความจำไม่ใช่แคช
บทบาทของการแคชในการพัฒนาธุรกิจมีบทบาทสำคัญและสามารถลดภาระของทรัพยากรเวลาอวกาศ แต่ควรสังเกตว่าคุณไม่ควรใช้หน่วยความจำเป็นแคชได้อย่างง่ายดาย หน่วยความจำเป็นสิ่งที่เป็นที่ดินทุกนิ้วสำหรับการพัฒนาโปรแกรมใด ๆ หากไม่ใช่ทรัพยากรที่สำคัญมากโปรดอย่าวางไว้ในหน่วยความจำโดยตรงหรือกำหนดกลไกการหมดอายุเพื่อทำลายแคชหมดอายุโดยอัตโนมัติ
4. ตรวจสอบการใช้หน่วยความจำของ JavaScript
ในการพัฒนาประจำวันเรายังสามารถใช้เครื่องมือบางอย่างในการวิเคราะห์และแก้ไขปัญหาการใช้หน่วยความจำใน JavaScript
4.1 เบราว์เซอร์ Blink/WebKit
ในเบราว์เซอร์ Blink/Webkit (Chrome, Safari, Opera ฯลฯ ) เราสามารถใช้เครื่องมือโปรไฟล์ของเครื่องมือนักพัฒนาเพื่อทำการตรวจสอบหน่วยความจำในโปรแกรมของเรา
4.2 การตรวจสอบหน่วยความจำใน node.js
ใน node.js เราสามารถใช้โมดูล Node-Heapdump และ Node-Memwatch สำหรับการตรวจสอบหน่วยความจำ
การคัดลอกรหัสมีดังนี้:
var heapdump = ต้องการ ('heapdump');
var fs = ต้องการ ('fs');
var path = ต้องการ ('เส้นทาง');
fs.writefilesync (path.join (__ dirname, 'app.pid'), process.pid);
-
การคัดลอกรหัสมีดังนี้: <span style = "Font-Family: Georgia, 'Times New Roman', 'BitStream Charter', Times, Serif; Font-Size: 14px; Line-Height: 1.5EM;" ของหน่วยความจำกอง </span>
คัดลอกรหัสดังนี้: $ kill -USR2 (cat app.pid)
ด้วยวิธีนี้จะมีไฟล์สแน็ปช็อตที่มีชื่ออยู่ในรูปแบบ heapdump- <sec>. <usec> .heapsnapshot ในไดเรกทอรีไฟล์ เราสามารถเปิดได้โดยใช้เครื่องมือโปรไฟล์ในเครื่องมือนักพัฒนาของเบราว์เซอร์และตรวจสอบ
5. สรุป
บทความกำลังจะมาอีกครั้งในไม่ช้า การแบ่งปันนี้ส่วนใหญ่จะแสดงเนื้อหาต่อไปนี้:
1. JavaScript เกี่ยวข้องอย่างใกล้ชิดกับการใช้หน่วยความจำในระดับภาษา
2. การจัดการหน่วยความจำและกลไกการรีไซเคิลใน JavaScript;
3. วิธีการใช้หน่วยความจำอย่างมีประสิทธิภาพมากขึ้นเพื่อให้จาวาสคริปต์ที่ผลิตสามารถขยายได้และมีพลังมากขึ้น
4. วิธีการตรวจสอบหน่วยความจำเมื่อพบปัญหาหน่วยความจำ
ฉันหวังว่าจากการเรียนรู้บทความนี้คุณสามารถสร้างรหัส JavaScript ที่ดีขึ้นเพื่อให้แม่ของคุณรู้สึกสบายใจและเจ้านายของคุณรู้สึกสบายใจ