# สร้างแอปธนาคาร ตอนที่ 3: วิธีการดึงและใช้งานข้อมูล ลองนึกถึงคอมพิวเตอร์ของ Enterprise ใน Star Trek - เมื่อกัปตัน Picard ขอข้อมูลสถานะของยาน ข้อมูลจะปรากฏขึ้นทันทีโดยที่อินเทอร์เฟซไม่ต้องปิดและสร้างใหม่ทั้งหมด การไหลลื่นของข้อมูลแบบนี้คือสิ่งที่เรากำลังสร้างด้วยการดึงข้อมูลแบบไดนามิก ตอนนี้แอปธนาคารของคุณเหมือนกับหนังสือพิมพ์ที่พิมพ์ออกมา - มีข้อมูลแต่ไม่เปลี่ยนแปลง เราจะเปลี่ยนมันให้เป็นเหมือนศูนย์ควบคุมภารกิจของ NASA ที่ข้อมูลไหลเวียนอย่างต่อเนื่องและอัปเดตแบบเรียลไทม์โดยไม่รบกวนการทำงานของผู้ใช้ คุณจะได้เรียนรู้วิธีการสื่อสารกับเซิร์ฟเวอร์แบบอะซิงโครนัส จัดการข้อมูลที่มาถึงในเวลาต่างกัน และเปลี่ยนข้อมูลดิบให้เป็นสิ่งที่มีความหมายสำหรับผู้ใช้ นี่คือความแตกต่างระหว่างการสาธิตและซอฟต์แวร์ที่พร้อมใช้งานจริง ## แบบทดสอบก่อนเรียน [แบบทดสอบก่อนเรียน](https://ff-quizzes.netlify.app/web/quiz/45) ### สิ่งที่ต้องเตรียมก่อนเริ่ม ก่อนที่จะเริ่มต้นการดึงข้อมูล ให้แน่ใจว่าคุณมีสิ่งเหล่านี้พร้อม: - **บทเรียนก่อนหน้า**: ทำแบบฟอร์ม [เข้าสู่ระบบและลงทะเบียน](../2-forms/README.md) ให้เสร็จ - เราจะใช้เป็นพื้นฐานในการสร้าง - **เซิร์ฟเวอร์ในเครื่อง**: ติดตั้ง [Node.js](https://nodejs.org) และ [เรียกใช้ API เซิร์ฟเวอร์](../api/README.md) เพื่อให้ข้อมูลบัญชี - **การเชื่อมต่อ API**: ทดสอบการเชื่อมต่อเซิร์ฟเวอร์ของคุณด้วยคำสั่งนี้: ```bash curl http://localhost:5000/api # Expected response: "Bank API v1.0.0" ``` การทดสอบอย่างรวดเร็วนี้ช่วยให้มั่นใจว่าทุกองค์ประกอบสามารถสื่อสารกันได้อย่างถูกต้อง: - ตรวจสอบว่า Node.js ทำงานได้อย่างถูกต้องในระบบของคุณ - ยืนยันว่าเซิร์ฟเวอร์ API ของคุณทำงานและตอบสนอง - ตรวจสอบว่าแอปของคุณสามารถเข้าถึงเซิร์ฟเวอร์ได้ (เหมือนการตรวจสอบการติดต่อวิทยุก่อนเริ่มภารกิจ) --- ## การทำความเข้าใจการดึงข้อมูลในแอปเว็บสมัยใหม่ วิธีที่แอปพลิเคชันเว็บจัดการข้อมูลได้พัฒนาขึ้นอย่างมากในช่วงสองทศวรรษที่ผ่านมา การทำความเข้าใจวิวัฒนาการนี้จะช่วยให้คุณเข้าใจว่าทำไมเทคนิคสมัยใหม่อย่าง AJAX และ Fetch API ถึงมีประสิทธิภาพและกลายเป็นเครื่องมือสำคัญสำหรับนักพัฒนาเว็บ มาสำรวจดูว่าการทำงานของเว็บไซต์แบบดั้งเดิมแตกต่างจากแอปพลิเคชันที่ตอบสนองและไดนามิกในปัจจุบันอย่างไร ### แอปพลิเคชันแบบหลายหน้า (MPA) ในยุคแรกของเว็บ ทุกครั้งที่คลิกเหมือนกับการเปลี่ยนช่องบนโทรทัศน์เก่า - หน้าจอจะว่างเปล่า แล้วค่อยๆ ปรับเข้าสู่เนื้อหาใหม่ นี่คือความจริงของแอปพลิเคชันเว็บในยุคแรก ที่ทุกการโต้ตอบหมายถึงการสร้างหน้าใหม่ทั้งหมดจากศูนย์ ```mermaid sequenceDiagram participant User participant Browser participant Server User->>Browser: Clicks link or submits form Browser->>Server: Requests new HTML page Note over Browser: Page goes blank Server->>Browser: Returns complete HTML page Browser->>User: Displays new page (flash/reload) ``` ![กระบวนการอัปเดตในแอปพลิเคชันแบบหลายหน้า](../../../../translated_images/mpa.7f7375a1a2d4aa779d3f928a2aaaf9ad76bcdeb05cfce2dc27ab126024050f51.th.png) **ทำไมวิธีนี้ถึงดูไม่ราบรื่น:** - ทุกครั้งที่คลิกหมายถึงการสร้างหน้าใหม่ทั้งหมด - ผู้ใช้ถูกขัดจังหวะกลางความคิดด้วยการกระพริบหน้าจอที่น่ารำคาญ - การเชื่อมต่ออินเทอร์เน็ตทำงานหนักเพื่อดาวน์โหลดส่วนหัวและส่วนท้ายซ้ำๆ - แอปพลิเคชันรู้สึกเหมือนการค้นหาเอกสารในตู้เก็บเอกสารมากกว่าการใช้ซอฟต์แวร์ ### แอปพลิเคชันแบบหน้าเดียว (SPA) AJAX (Asynchronous JavaScript and XML) เปลี่ยนแปลงรูปแบบนี้ไปอย่างสิ้นเชิง เหมือนกับการออกแบบแบบโมดูลของสถานีอวกาศนานาชาติ ที่นักบินอวกาศสามารถเปลี่ยนส่วนประกอบแต่ละส่วนได้โดยไม่ต้องสร้างโครงสร้างทั้งหมดใหม่ AJAX ช่วยให้เราสามารถอัปเดตส่วนเฉพาะของหน้าเว็บได้โดยไม่ต้องโหลดใหม่ทั้งหมด แม้ว่าชื่อจะกล่าวถึง XML แต่ปัจจุบันเราใช้ JSON เป็นหลัก แต่หลักการสำคัญยังคงเหมือนเดิม: อัปเดตเฉพาะสิ่งที่ต้องเปลี่ยนแปลง ```mermaid sequenceDiagram participant User participant Browser participant JavaScript participant Server User->>Browser: Interacts with page Browser->>JavaScript: Triggers event handler JavaScript->>Server: Fetches only needed data Server->>JavaScript: Returns JSON data JavaScript->>Browser: Updates specific page elements Browser->>User: Shows updated content (no reload) ``` ![กระบวนการอัปเดตในแอปพลิเคชันแบบหน้าเดียว](../../../../translated_images/spa.268ec73b41f992c2a21ef9294235c6ae597b3c37e2c03f0494c2d8857325cc57.th.png) **ทำไม SPA ถึงดีกว่า:** - อัปเดตเฉพาะส่วนที่เปลี่ยนแปลงจริงๆ (ฉลาดใช่ไหม?) - ไม่มีการขัดจังหวะที่น่ารำคาญ - ผู้ใช้สามารถทำงานต่อได้อย่างต่อเนื่อง - ข้อมูลที่เดินทางผ่านเครือข่ายน้อยลง หมายถึงการโหลดที่เร็วขึ้น - ทุกอย่างรู้สึกเร็วและตอบสนองได้ดี เหมือนแอปบนมือถือของคุณ ### การพัฒนาไปสู่ Fetch API สมัยใหม่ เบราว์เซอร์สมัยใหม่มี [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API) ซึ่งแทนที่ [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) แบบเก่า เหมือนกับความแตกต่างระหว่างการใช้โทรเลขและการใช้อีเมล Fetch API ใช้ promises เพื่อเขียนโค้ดอะซิงโครนัสที่สะอาดขึ้นและจัดการ JSON ได้อย่างเป็นธรรมชาติ | คุณสมบัติ | XMLHttpRequest | Fetch API | |-----------|----------------|-----------| | **ไวยากรณ์** | ใช้ callback ที่ซับซ้อน | ใช้ promises ที่สะอาด | | **การจัดการ JSON** | ต้องแปลงด้วยตนเอง | มี `.json()` ในตัว | | **การจัดการข้อผิดพลาด** | ข้อมูลข้อผิดพลาดจำกัด | รายละเอียดข้อผิดพลาดครบถ้วน | | **การสนับสนุนสมัยใหม่** | รองรับแบบเก่า | ใช้ promises และ async/await ของ ES6+ | > 💡 **ความเข้ากันได้ของเบราว์เซอร์**: ข่าวดี - Fetch API ใช้งานได้ในเบราว์เซอร์สมัยใหม่ทั้งหมด! หากคุณอยากรู้เกี่ยวกับเวอร์ชันเฉพาะ [caniuse.com](https://caniuse.com/fetch) มีข้อมูลความเข้ากันได้ครบถ้วน > **สรุป:** - ใช้งานได้ดีใน Chrome, Firefox, Safari และ Edge (พื้นฐานที่ผู้ใช้ของคุณอยู่) - Internet Explorer เท่านั้นที่ต้องการความช่วยเหลือเพิ่มเติม (และจริงๆ ถึงเวลาปล่อย IE ไปแล้ว) - เตรียมพร้อมสำหรับรูปแบบ async/await ที่สง่างามที่เราจะใช้ในภายหลัง ### การสร้างระบบเข้าสู่ระบบและการดึงข้อมูลบัญชี ตอนนี้เรามาสร้างระบบเข้าสู่ระบบที่เปลี่ยนแอปธนาคารของคุณจากการแสดงผลแบบคงที่ไปเป็นแอปพลิเคชันที่ใช้งานได้จริง เหมือนกับโปรโตคอลการตรวจสอบสิทธิ์ที่ใช้ในสถานที่ปลอดภัยของทหาร เราจะตรวจสอบข้อมูลรับรองของผู้ใช้และให้สิทธิ์เข้าถึงข้อมูลเฉพาะของพวกเขา เราจะสร้างสิ่งนี้ทีละขั้นตอน โดยเริ่มจากการตรวจสอบสิทธิ์พื้นฐานและเพิ่มความสามารถในการดึงข้อมูล #### ขั้นตอนที่ 1: สร้างฟังก์ชันพื้นฐานสำหรับการเข้าสู่ระบบ เปิดไฟล์ `app.js` ของคุณและเพิ่มฟังก์ชัน `login` ใหม่ ฟังก์ชันนี้จะจัดการกระบวนการตรวจสอบสิทธิ์ของผู้ใช้: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **มาดูรายละเอียดกัน:** - คำว่า `async`? มันบอก JavaScript ว่า "เฮ้ ฟังก์ชันนี้อาจต้องรออะไรบางอย่าง" - เรากำลังดึงฟอร์มจากหน้า (แค่หาโดยใช้ ID) - จากนั้นเราก็ดึงข้อมูลที่ผู้ใช้พิมพ์เป็นชื่อผู้ใช้ - นี่คือเคล็ดลับที่ดี: คุณสามารถเข้าถึงอินพุตของฟอร์มใดๆ โดยใช้แอตทริบิวต์ `name` - ไม่ต้องใช้ getElementById เพิ่มเติม! > 💡 **รูปแบบการเข้าถึงฟอร์ม**: ทุกการควบคุมฟอร์มสามารถเข้าถึงได้โดยใช้ชื่อ (ตั้งค่าใน HTML ด้วยแอตทริบิวต์ `name`) เป็น property ของ element ฟอร์ม ซึ่งให้วิธีการที่สะอาดและอ่านง่ายในการดึงข้อมูลฟอร์ม #### ขั้นตอนที่ 2: สร้างฟังก์ชันดึงข้อมูลบัญชี ต่อไป เราจะสร้างฟังก์ชันเฉพาะเพื่อดึงข้อมูลบัญชีจากเซิร์ฟเวอร์ ซึ่งจะใช้รูปแบบเดียวกับฟังก์ชันการลงทะเบียนของคุณ แต่เน้นที่การดึงข้อมูล: ```javascript async function getAccount(user) { try { const response = await fetch('//localhost:5000/api/accounts/' + encodeURIComponent(user)); return await response.json(); } catch (error) { return { error: error.message || 'Unknown error' }; } } ``` **สิ่งที่โค้ดนี้ทำได้:** - **ใช้** Fetch API สมัยใหม่เพื่อร้องขอข้อมูลแบบอะซิงโครนัส - **สร้าง** URL คำขอ GET พร้อมพารามิเตอร์ชื่อผู้ใช้ - **ใช้** `encodeURIComponent()` เพื่อจัดการอักขระพิเศษใน URL อย่างปลอดภัย - **แปลง** การตอบกลับเป็นรูปแบบ JSON เพื่อการจัดการข้อมูลที่ง่าย - **จัดการ** ข้อผิดพลาดอย่างมีประสิทธิภาพโดยการส่งคืนวัตถุข้อผิดพลาดแทนการหยุดทำงาน > ⚠️ **หมายเหตุด้านความปลอดภัย**: ฟังก์ชัน `encodeURIComponent()` จัดการอักข สำหรับเนื้อหาที่ซับซ้อนมากขึ้น ให้ใช้ [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) ร่วมกับเมธอด [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append): ```javascript // Safe way to create new elements const transactionItem = document.createElement('div'); transactionItem.className = 'transaction-item'; transactionItem.textContent = `${transaction.date}: ${transaction.description}`; container.append(transactionItem); ``` **ทำความเข้าใจวิธีนี้:** - **สร้าง**องค์ประกอบ DOM ใหม่ด้วยโปรแกรม - **ควบคุม**คุณสมบัติและเนื้อหาขององค์ประกอบได้อย่างเต็มที่ - **รองรับ**โครงสร้างองค์ประกอบที่ซับซ้อนและซ้อนกัน - **รักษา**ความปลอดภัยโดยแยกโครงสร้างออกจากเนื้อหา > ⚠️ **ข้อควรระวังด้านความปลอดภัย**: แม้ว่า [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) จะปรากฏในบทเรียนหลายๆ แห่ง แต่สามารถรันสคริปต์ที่ฝังอยู่ได้ เช่นเดียวกับมาตรการรักษาความปลอดภัยที่ CERN ที่ป้องกันการรันโค้ดที่ไม่ได้รับอนุญาต การใช้ `textContent` และ `createElement` เป็นทางเลือกที่ปลอดภัยกว่า > **ความเสี่ยงของ innerHTML:** - รันแท็ก `