อย่างไรก็ตามตราบใดที่การรีเฟรชไม่สามารถทำซ้ำได้หลังจากเกิดข้อผิดพลาด JavaScript ผู้ใช้สามารถแก้ปัญหาได้ด้วยการรีเฟรชและเบราว์เซอร์จะไม่พังและมันจะดีถ้ามันไม่ได้เกิดขึ้น สมมติฐานนี้เป็นจริงก่อนที่แอปหน้าเดียวจะได้รับความนิยม แอพหน้าเดียวในปัจจุบันมีความซับซ้อนอย่างมากหลังจากทำงานเป็นระยะเวลาหนึ่ง คุณจะไม่ทำงานใหม่ในการดำเนินการก่อนหน้านี้หรือไม่? ดังนั้นจึงยังจำเป็นที่เราจะต้องจับและวิเคราะห์ข้อมูลข้อยกเว้นเหล่านี้จากนั้นเราสามารถแก้ไขรหัสเพื่อหลีกเลี่ยงการส่งผลกระทบต่อประสบการณ์ผู้ใช้
วิธีจับข้อยกเว้น เราเขียนตัวเอง throw new Error()
ซึ่งเราสามารถจับภาพได้อย่างแน่นอนถ้าเราต้องการจับภาพเพราะเรารู้ดีว่า throw
เขียนอะไรอยู่ อย่างไรก็ตามข้อยกเว้นที่เกิดขึ้นเมื่อเรียกเบราว์เซอร์ API ไม่จำเป็นต้องจับได้ง่าย สำหรับอดีตเรายังสามารถจับมันได้ผ่าน try-catch
สำหรับหลังเราต้องฟังข้อยกเว้นระดับโลกแล้วจับมัน
หาก API ของเบราว์เซอร์บางตัวเป็นที่รู้จักกันในการโยนข้อยกเว้นเราจำเป็นต้องนำการโทรเข้าสู่ try-catch
เพื่อหลีกเลี่ยงโปรแกรมทั้งหมดที่เข้าสู่สถานะที่ผิดกฎหมายเนื่องจากข้อผิดพลาด ตัวอย่างเช่น window.localStorage
เป็น API
try {
localstorage.setItem ('วันที่', date.now ());
} catch (ข้อผิดพลาด) {
Reporterror (ข้อผิดพลาด);
-
สถานการณ์ที่ใช้ try-catch
ได้ทั่วไปอีกประการหนึ่งคือการโทรกลับ เนื่องจากรหัสของฟังก์ชั่นการโทรกลับไม่สามารถควบคุมได้เราจึงไม่ทราบว่ารหัสนั้นดีแค่ไหนและ API อื่น ๆ ที่มีข้อยกเว้นจะถูกเรียกหรือไม่ เพื่อไม่ให้เรียกใช้รหัสอื่น ๆ หลังจากโทรกลับเนื่องจากข้อผิดพลาดในการโทรกลับจำเป็นต้องนำการโทรกลับเข้าสู่ try-catch
listeners.forEach(function(listener) {
พยายาม {
ผู้ฟัง ();
} catch (ข้อผิดพลาด) {
Reporterror (ข้อผิดพลาด);
-
-
สำหรับสถานที่ที่ try-catch
ไม่สามารถครอบคลุมได้หากมีข้อยกเว้นเกิดขึ้นมันสามารถถูกจับได้ผ่าน window.onerror
เท่านั้น
window.onerror =
ฟังก์ชั่น (errorMessage, scripturi, ผ้าลินิน) {
Reporterror ({
ข้อความ: errormessage,
สคริปต์: Scripturi,
บรรทัด: ผ้าลินิน
-
-
ระวังอย่าให้ฉลาดและใช้ window.addEventListener
หรือ window.attachEvent
เพื่อฟัง window.onerror
เบราว์เซอร์จำนวนมากใช้ window.onerror
หรือ window.onerror
เท่านั้นการใช้งานเป็นมาตรฐาน เมื่อพิจารณาว่าร่างมาตรฐานยังกำหนด window.onerror
เราแค่ต้องใช้ window.onerror
สมมติว่าเรามีฟังก์ชั่น reportError
เพื่อรวบรวมข้อยกเว้นที่จับได้จากนั้นส่งไปยังที่เก็บข้อมูลฝั่งเซิร์ฟเวอร์ในแบตช์สำหรับการสืบค้นและการวิเคราะห์เราต้องการรวบรวมข้อมูลอะไร ข้อมูลที่มีประโยชน์เพิ่มเติมรวมถึง: ประเภทข้อผิดพลาด ( name
), ข้อความแสดงข้อผิดพลาด ( message
), ที่อยู่ไฟล์สคริปต์ ( script
), หมายเลขบรรทัด ( line
), หมายเลขคอลัมน์ ( column
) และสแต็กติดตาม ( stack
) หากข้อยกเว้นถูกจับได้ผ่าน try-catch
ข้อมูลทั้งหมดเหล่านี้อยู่ในวัตถุ Error
(สนับสนุนโดยเบราว์เซอร์กระแสหลัก) ดังนั้น reportError
ยังสามารถรวบรวมข้อมูลนี้ได้ แต่ถ้ามันถูกจับผ่าน window.onerror
เราทุกคนรู้ว่าฟังก์ชั่นเหตุการณ์นี้มีพารามิเตอร์เพียง 3 ตัวดังนั้นข้อมูลที่ไม่คาดคิดของพารามิเตอร์ทั้ง 3 นี้จะหายไป
หากวัตถุ Error
ถูกสร้างขึ้นด้วยตัวเราเอง error.message
จะถูกควบคุมโดยเรา โดยพื้นฐานแล้วสิ่งที่เราใส่ลงไปใน error.message
อะไรจะเป็นพารามิเตอร์แรก ( message
) ของ window.onerror
(เบราว์เซอร์จะทำการแก้ไขเล็กน้อยเช่นการเพิ่ม 'Uncaught Error: '
คำนำหน้า) ดังนั้นเราจึงสามารถทำให้แอตทริบิวต์ที่เรากังวลเกี่ยวกับ (เช่น JSON.Stringify
) และเก็บไว้ใน error.message
พวกเขาอยู่ใน window.onerror
แน่นอนว่าสิ่งนี้ จำกัด เฉพาะวัตถุ Error
ที่เราสร้างขึ้นเอง
ผู้ผลิตเบราว์เซอร์ยังทราบถึงข้อ จำกัด ที่ผู้คนต้องใช้เมื่อใช้ window.onerror
ดังนั้นพวกเขาจึงเริ่มเพิ่มพารามิเตอร์ใหม่ลงใน window.onerror
เมื่อพิจารณาว่ามีเพียงหมายเลขแถวและหมายเลขคอลัมน์ที่ดูเหมือนจะสมมาตรมากเช่นเพิ่มหมายเลขคอลัมน์ก่อนและวางไว้ในพารามิเตอร์ที่สี่ อย่างไรก็ตามสิ่งที่ทุกคนมีความกังวลมากขึ้นคือว่าพวกเขาจะได้รับสแต็คที่สมบูรณ์หรือไม่ดังนั้น Firefox จึงบอกว่ามันจะดีกว่าที่จะวางสแต็กในพารามิเตอร์ที่ห้า แต่ Chrome กล่าวว่ามันจะดีกว่าที่จะใส่วัตถุ Error
ทั้งหมดในพารามิเตอร์ที่ห้าและคุณสามารถอ่านแอตทริบิวต์ใด ๆ รวมถึงแอตทริบิวต์ที่กำหนดเอง เป็นผลให้ Chrome เคลื่อนที่เร็วขึ้น window.onerror
ที่มีความรับผิดชอบถูกนำมาใช้ใน Chrome 30 ส่งผลให้การเขียนร่างมาตรฐานดังต่อไปนี้
ความสม่ำเสมอของคุณลักษณะwindow.onerror = function(
errormessage,
Scripturi
ผ้าลินิน
คอลัมน์
ข้อผิดพลาด
-
ถ้า (ข้อผิดพลาด) {
Reporterror (ข้อผิดพลาด);
} อื่น {
Reporterror ({
ข้อความ: errormessage,
สคริปต์: Scripturi,
บรรทัด: ผ้าลินิน
คอลัมน์: คอลัมน์
-
-
-
ชื่อของคุณลักษณะ script
วัตถุข้อ Error
Error
ที่เราพูดถึงก่อนหน้านี้จะขึ้นอยู่กับวิธีการ filename
ชื่อ Chrome ดังนั้นเราจึงต้องใช้ฟังก์ชั่นพิเศษเพื่อทำให้วัตถุ Error
เป็นปกตินั่นคือเพื่อแมปชื่อแอตทริบิวต์ที่แตกต่างกับชื่อแอตทริบิวต์แบบครบวงจร สำหรับการปฏิบัติเฉพาะโปรดดูบทความนี้ แม้ว่าการใช้เบราว์เซอร์จะได้รับการอัปเดต แต่ก็ไม่ยากเกินไปที่มนุษย์จะรักษาตารางการทำแผนที่ดังกล่าว
ที่คล้ายกันคือรูปแบบของการติดตาม stack
คุณสมบัตินี้บันทึกข้อมูลสแต็กของข้อยกเว้นเมื่อมันเกิดขึ้นในรูปแบบของข้อความธรรมดา . ชื่อ ( identifier
), ไฟล์ ( script
), หมายเลขบรรทัด ( line
) และหมายเลขคอลัมน์ ( column
)
หากคุณพบข้อผิดพลาดกับข้อความ 'Script error.'
คุณจะเข้าใจสิ่งที่ฉันกำลังพูดถึงซึ่งเป็นข้อ จำกัด ของเบราว์เซอร์สำหรับไฟล์สคริปต์จากแหล่งต่าง ๆ เหตุผลสำหรับข้อ จำกัด ด้านความปลอดภัยนี้มีดังนี้: สมมติว่า HTML ที่ส่งคืนโดยนายธนาคารออนไลน์หลังจากการเข้าสู่ระบบนั้นแตกต่างจาก HTML ที่ผู้ใช้ที่ไม่ระบุชื่อเห็นเว็บไซต์บุคคลที่สามสามารถนำ URI ของธนาคารออนไลน์นี้ลงใน script.src
แอตทริบิวต์ script.src
แน่นอนว่า HTML ไม่สามารถแยกวิเคราะห์เป็น JS ได้ดังนั้นเบราว์เซอร์จะทำการยกเว้นและเว็บไซต์ของบุคคลที่สามนี้สามารถตรวจสอบได้ว่าผู้ใช้เข้าสู่ระบบโดยวิเคราะห์ตำแหน่งของข้อยกเว้นหรือไม่ ด้วยเหตุนี้เบราว์เซอร์จะกรองข้อยกเว้นทั้งหมดที่ถูกส่งโดยไฟล์สคริปต์ต้นทางที่แตกต่างกันโดยเหลือเพียงข้อความที่ไม่เปลี่ยนแปลงเช่น 'Script error.'
และแอตทริบิวต์อื่น ๆ ทั้งหมดจะหายไป
สำหรับเว็บไซต์ในระดับหนึ่งมันเป็นเรื่องปกติสำหรับไฟล์สคริปต์ที่จะวางไว้บน CDN และแหล่งที่มาที่แตกต่างกัน ตอนนี้แม้ว่าคุณจะสร้างเว็บไซต์ขนาดเล็กด้วยตัวคุณเองเฟรมเวิร์กทั่วไปเช่น jQuery และ Backbone สามารถอ้างอิงเวอร์ชันบน CDN สาธารณะโดยตรงเพื่อเพิ่มความเร็วในการดาวน์โหลดผู้ใช้ ดังนั้นข้อ จำกัด ด้านความปลอดภัยนี้ทำให้เกิดปัญหาบางอย่างทำให้ข้อมูลข้อยกเว้นที่เรารวบรวมจาก Chrome และ Firefox เป็น 'Script error.'
ที่ไร้ประโยชน์
หากคุณต้องการหลีกเลี่ยงข้อ จำกัด นี้เพียงตรวจสอบให้แน่ใจว่าไฟล์สคริปต์และหน้านั้นเหมือนกัน แต่จะไม่วางไฟล์สคริปต์บนเซิร์ฟเวอร์ที่ไม่เร่งความเร็วโดย CDN ลดความเร็วในการดาวน์โหลดของผู้ใช้หรือไม่? ทางออกหนึ่งคือการวางไฟล์สคริปต์ต่อไปบน CDN ให้ใช้ XMLHttpRequest
เพื่อดาวน์โหลดเนื้อหากลับผ่าน CORS จากนั้นสร้างแท็ก <script>
เพื่อฉีดเข้าไปในหน้า รหัสที่ฝังอยู่ในหน้านั้นเป็นแหล่งกำเนิดเดียวกัน
นี่เป็นเรื่องง่ายที่จะพูด แต่มีรายละเอียดมากมายที่จะนำไปใช้ เพื่อให้ตัวอย่างง่ายๆ:
<script src="http://cdn.com/step1.js"></script>
<script>
(ฟังก์ชั่น step2 () {}) ();
</script>
<script src = "http://cdn.com/step3.js"> </script>
เราทุกคนรู้ว่าหากมีการพึ่งพาในขั้นตอนที่ 1, ขั้นตอนที่ 2 และขั้นตอนที่ 3 จะต้องดำเนินการอย่างเคร่งครัดในลำดับนี้มิฉะนั้นอาจเกิดข้อผิดพลาด เบราว์เซอร์สามารถขอไฟล์ STEP1 และ STEP3 ในแบบขนาน แต่รับประกันคำสั่งซื้อเมื่อดำเนินการ หากเราได้รับเนื้อหาไฟล์ของขั้นตอนที่ 1 และขั้นตอนที่ 3 โดยใช้ XMLHttpRequest
เราจำเป็นต้องตรวจสอบลำดับที่ถูกต้องของเราเอง นอกจากนี้อย่าลืมขั้นตอนที่ 2
หากเรามีชุดเครื่องมือที่สมบูรณ์เพื่อสร้างแท็ก <script>
สำหรับหน้าต่างๆบนเว็บไซต์เราจำเป็นต้องปรับชุดเครื่องมือนี้เพื่อทำการเปลี่ยนแปลงแท็ก <script>
:
<script>
SchedulerEmotescript ('http://cdn.com/step1.js');
</script>
<script>
ScheduceInlInescript (รหัสฟังก์ชัน () {
(ฟังก์ชั่น step2 () {}) ();
-
</script>
<script>
SchedulerEmotescript ('http://cdn.com/step3.js');
</script>
เราจำเป็นต้องใช้ฟังก์ชั่นทั้งสองของ scheduleRemoteScript
และ scheduleInlineScript
และตรวจสอบให้แน่ใจว่าพวกเขาถูกกำหนดไว้ก่อนแท็ก <script>
แรกที่อ้างอิงไฟล์สคริปต์ภายนอกจากนั้นแท็ก <script>
ที่เหลือจะถูกเขียนลงในรูปแบบข้างต้น โปรดทราบว่าฟังก์ชั่น step2
ที่ถูกดำเนินการทันทีถูกวางไว้ในฟังก์ชัน code
ที่ใหญ่กว่า ฟังก์ชั่น code
จะไม่ถูกเรียกใช้งานมันเป็นเพียงคอนเทนเนอร์เพื่อให้สามารถเก็บรหัส step2 ดั้งเดิมได้โดยไม่ต้องหลบหนี แต่จะไม่ถูกดำเนินการทันที
ต่อไปเราจำเป็นต้องใช้กลไกที่สมบูรณ์เพื่อให้แน่ใจว่าเนื้อหาไฟล์ที่ดาวน์โหลดโดย scheduleRemoteScript
ตามที่อยู่และรหัสที่ได้รับโดยตรงจาก scheduleInlineScript
สามารถดำเนินการทีละหนึ่งในลำดับที่ถูกต้อง ฉันจะไม่ให้รหัสรายละเอียดที่นี่
การรับเนื้อหาผ่าน CORS และการฉีดรหัสลงในหน้าสามารถผ่านข้อ จำกัด ด้านความปลอดภัยได้ แต่มันจะแนะนำปัญหาใหม่นั่นคือความขัดแย้งหมายเลขบรรทัด ในขั้นต้นไฟล์สคริปต์ที่ไม่ซ้ำกันสามารถอยู่ผ่าน error.script
ได้ข้อความจากนั้นหมายเลขบรรทัดที่ไม่ซ้ำกันสามารถอยู่ได้ผ่าน error.line
ตอนนี้เนื่องจากรหัสทั้งหมดที่ฝังอยู่ในหน้าแท็ก <script>
<script>
แท็กไม่สามารถแยกแยะได้โดย error.script
. ตำแหน่งซอร์สโค้ดที่มีข้อมูลข้อยกเว้น
เพื่อหลีกเลี่ยงความขัดแย้งหมายเลขบรรทัดเราสามารถเสียหมายเลขบรรทัดบางอย่างเพื่อให้ช่วงเวลาหมายเลขบรรทัดที่ใช้โดยรหัสจริงในแต่ละแท็ก <script>
ไม่ทับซ้อนกัน ตัวอย่างเช่นสมมติว่ารหัสจริงในแต่ละแท็ก <script>
ไม่เกิน 1,000 บรรทัดจากนั้นฉันสามารถปล่อยให้รหัสในแท็ก <script>
แรกใช้บรรทัด 11000 และปล่อยให้แท็ก <script>
ที่สองในรหัสในรหัส ใช้สาย 10012000 (1,000 สายเปล่าที่ใส่ไว้ก่อนที่จะแทรก) รหัสของแท็ก <script>
ที่สามใช้บรรทัด 20013000 (สายเปล่า 2000 ที่ใส่ไว้ก่อนที่จะแทรก) และอื่น ๆ จากนั้นเราใช้แอตทริบิวต์ data-*
เพื่อบันทึกข้อมูลนี้เพื่อการตรวจสอบย้อนกลับได้ง่าย
<script
data-src = "http://cdn.com/step1.js"
Data-line-start = "1"
-
// รหัสสำหรับขั้นตอนที่ 1
</script>
<สคริปต์ data-line-start = "1001">
// '/n' * 1000
// รหัสสำหรับขั้นตอนที่ 2
</script>
<สคริปต์
data-src = "http://cdn.com/step3.js"
Data-line-start = "2001"
-
// '/n' * 2000
// รหัสสำหรับขั้นตอนที่ 3
</script>
หลังจากการประมวลผลนี้หากเกิด error.line
ผิดพลาดคือ 3005
หมายความว่า error.script
จริงควรเป็น 'http://cdn.com/step3.js'
ในขณะที่ error.line
จริงควรเป็น 5
เราสามารถกรอกหมายเลขบรรทัดนี้ย้อนกลับตรวจสอบในฟังก์ชั่น reportError
ที่กล่าวถึงก่อนหน้านี้
แน่นอนเนื่องจากเราไม่สามารถรับประกันได้ว่าแต่ละไฟล์สคริปต์มีเพียง 1,000 บรรทัดจึงเป็นไปได้ว่าไฟล์สคริปต์บางไฟล์มีน้อยกว่า 1,000 บรรทัดดังนั้นจึงไม่จำเป็นต้องจัดสรร 1,000 บรรทัดให้กับแท็ก <script>
แต่ละรายการ เราสามารถจัดสรรช่วงเวลาตามจำนวนสคริปต์ที่แท้จริงเพียงตรวจสอบให้แน่ใจว่าช่วงเวลาที่ใช้โดยแต่ละแท็ก <script>
ไม่ทับซ้อนกัน
ข้อ จำกัด ด้านความปลอดภัยที่กำหนดโดยเบราว์เซอร์เกี่ยวกับเนื้อหาจากแหล่งต่าง ๆ นั้นไม่ได้ จำกัด อยู่ที่แท็ก <script>
เนื่องจาก XMLHttpRequest
สามารถฝ่าฟันข้อ จำกัด นี้ผ่าน CORS ทำไมทรัพยากรจึงถูกอ้างอิงโดยตรงผ่านแท็กที่ไม่ได้รับอนุญาต? แน่นอนว่าโอเค
ข้อ จำกัด ของการอ้างอิงไปยังไฟล์สคริปต์ต้นทางที่แตกต่างกันสำหรับแท็ก <script>
ยังใช้กับการอ้างอิงถึงไฟล์ภาพต้นฉบับที่แตกต่างกันสำหรับแท็ก <img>
หากแท็ก <img>
เป็นแหล่งที่แตกต่างกันเมื่อใช้เมื่อวาด <canvas>
<canvas>
จะกลายเป็นสถานะการเขียนเท่านั้นเพื่อให้มั่นใจว่าเว็บไซต์ไม่สามารถขโมยข้อมูลภาพที่ไม่ได้รับอนุญาตจากแหล่งต่าง ๆ ผ่าน JavaScript ต่อมาแท็ก <img>
แก้ไขปัญหานี้โดยการแนะนำแอตทริบิวต์ crossorigin
หากใช้ crossorigin="anonymous"
" มันจะเทียบเท่ากับ cors ที่ไม่ระบุชื่อ;
เนื่องจากแท็ก <img>
สามารถทำสิ่งนี้ได้ทำไมแท็ก <script>
ถึงทำสิ่งนี้ไม่ได้? ดังนั้นผู้ผลิตเบราว์เซอร์จึงเพิ่มแอตทริบิวต์ crossorigin
เดียวกันลงในแท็ก <script>
เพื่อแก้ข้อ จำกัด ด้านความปลอดภัยข้างต้น ตอนนี้การสนับสนุน Chrome และ Firefox สำหรับสถานที่ให้บริการนี้ฟรีอย่างสมบูรณ์ Safari จะรักษา crossorigin="anonymous"
เป็น crossorigin="use-credentials"
และผลที่ได้คือถ้าเซิร์ฟเวอร์รองรับ Cors ที่ไม่ระบุชื่อเท่านั้น SAFARI จะถือว่าการรับรองความถูกต้องเป็นความล้มเหลว เนื่องจากเซิร์ฟเวอร์ CDN ได้รับการออกแบบมาเพื่อส่งคืนเนื้อหาแบบคงที่ด้วยเหตุผลด้านประสิทธิภาพจึงเป็นไปไม่ได้ที่จะส่งคืนส่วนหัว HTTP ที่จำเป็นในการตรวจสอบความถูกต้องของ CORS ตามคำขอ
การจัดการข้อยกเว้นของ JavaScript ดูง่ายและไม่แตกต่างจากภาษาอื่น ๆ แต่ไม่ใช่เรื่องง่ายที่จะจับข้อยกเว้นทั้งหมดและวิเคราะห์คุณสมบัติ แม้ว่าบริการของบุคคลที่สามบางแห่งจะให้บริการ Google Analytics ที่จับข้อยกเว้น JavaScript หากคุณต้องการเข้าใจรายละเอียดและหลักการคุณต้องทำด้วยตัวเอง