Monday 12 November 2012

เรียกใช้งาน JavaScript ในแบบ Modular โดยใช้ Require.js

สำหรับบทความนี้ผมอยากจะมาแนะนำเกี่ยวกับเทคนิคในการเรียกใช้งาน JavaScript ในแบบ Modular โดยใช้ Require.js ประโยชน์ของการใช้ Require.js คือ จะช่วยให้เราสามารถเรียกใช้งาน JavaScript ในแบบ Asynchronous (คือความสามารถในการ load หลายๆ file ได้พร้อมๆกัน) ทำให้สามารถ load เสร็จได้เร็วขึ้นกว่าการ load โดยใช้ script tag แบบปกติ แต่เป้าหมายจริงๆ ของ Require.js อยู่ที่การแบ่ง coding ออกให้เป็นสัดส่วน หรือเราเรียกว่า module แต่ละ module จะมีหน้าที่เฉพาะของตัวเอง หากเราต้องการใช้ เราก็ค่อยเรียกมาใช้งาน ซึ่งทำให้การเรียกใช้งานมีความยืดหยุ่น เรียกใช้งานได้รวดเร็ว และสามารถ maintain ได้ง่ายอีกด้วย นอกจากนั้น Require.js ยังมีความสามารถในเรื่องของการ load dependency ที่จำเป็นก่อนการเรียกใช้งานแต่ละ module ได้อีกด้วย เดี๋ยวเราลองมาดูวิธีการใช้งานแบบง่ายๆก่อนนะครับ ขั้นแรกเลย ก็ต้องไป download "require.js" มาก่อน (โดยเข้าไป download ได้จาก http://requirejs.org) จากนั้น วิธีการเรียกใช้งาน ให้เรียกใช้งานดังต่อไปนี้ครับ

<script data-main="scripts/main.js" src="scripts/require.js"></script>

วิธีการเรียกใช้งาน require.js ก็เหมือนกับการเรียกใช้งาน JavaScript อื่นๆโดยทั่วไป แต่ให้สังเกตุ attribute ที่ชื่อว่า data-main ซึ่งมีไว้เพื่อให้เรากำหนด JavaScript ที่ใช้เป็น file หลัก สำหรับที่เราจะเรียกใช้งาน module อื่นๆต่อไป (JavaScript ที่เรากำหนดไว้ใน data-main จะถูกเรียกใช้งานหลังจากที่ "require.js" ถูกโหลดเสร็จเรียบร้อย)

ต่อไป เราจะมาดู script ในส่วนของ main.js (จะตั้งชื่อเป็นอย่างอื่นก็ได้ แต่ถ้าตั้งเป็นชื่ออื่น ก็ต้องกำหนดค่าใน data-main ให้สัมพันธ์กันด้วย แค่นั้นเอง) หน้าที่ของ main.js ก็คือ เป็นไฟล์หลักที่ใช้สำหรับ load module อื่นๆ จะสังเกตุว่า ผมใช้คำว่า module จะไม่ใช้คำว่า script เพราะ Require.js พยายามให้เรามอง JavaScript เป็น module เดี๋ยวมาลองดูตัวอย่างกันก่อนแล้วกันนะครับ

main.js
======
require(["helper/util"], function(util) {
    util.hello();
});

ใน main.js เราเรียกใช้งาน function ที่ชื่อว่า require เพื่อ load "helper/util" module (ให้สังเกตุว่า ไม่ต้องใส่ .js เข้าไป เดี๋ยว require.js จะเติมให้เองโดยอัตโมมัติ) ส่วน path ในการเรียกใช้งาน ก็จะ relative จาก file ที่เรากำหนดให้เป็น file หลัก ซึ่งในที่นี้ก็คือ main.js นั่นเอง (เราสามารถกำหนดได้ว่า จะให้ require.js ไปมองหา module จากที่ไหน โดยการกำหนดค่า config ซึ่งในที่นี้ไม่อธิบายแล้วกันนะครับ เพราะมันจะยาวไป หากสนใจจริงๆ ก็เข้าไปอ่านได้ที่ http://requirejs.org/docs/api.html)

parameter ตัวแรก คือ array ของชื่อ module ที่เราต้องการ load ส่วน parameter ตัวที่สองคือ call function ที่จะถูกเรียกใช้งานเมื่อ module ที่เราต้องการถูก load ขึ้นมาเรียบร้อยแล้วนั่นเอง ให้สังเกตุว่ามีการส่งค่า util เข้าไปที่ function ด้วย นั่นหมายความว่า module ที่เรา load ในขณะนี้จะถูกส่งมาในตัวแปรที่ชื่อว่า util นั่นเองครับ ซึ่งภายใน function นี้ เราสามารถเรียกใช้งาน util.hello() ได้แล้วครับ

ส่วนต่อไป เดี๋ยวเราจะมาลองดูกันต่อใน script ส่วนที่เป็นการ define module ซึ่งจากตัวอย่างในที่นี้ก็คือ util.js ครับ

util.js
=====
define(function(){   
    var m = {};

    m.hello = function(){
        alert('Hello!');
    }

    return m;
});

ในส่วนของ util.js เราสร้าง Anonymous Function ขึ้นมา ซึ่งภายจะกำหนดค่าต่างๆ หรือจะทำอะไรก็แล้วแต่ แต่สุดท้ายจะต้องคืนค่า module กลับมา สำหรับในตัวอย่างนี้เราประกาศตัวแปรที่ชื่อว่า m เอาไว้สำหรับเก็บ namespace ที่เราสร้างขึ้นมาใหม่ โดยใช้ {} และภายใน namespace นี้ เราก็ประกาศ function ชื่อว่า hello() เอาไว้ เมื่อทุกอย่างเสร็จเรียบร้อย เราจะคืนค่า m กลับออกไป

สำหรับตัวอย่างที่ยกมาให้ดู อาจจะดูไม่ค่อยมีประโยชน์ในการนำไปใช้งานจริงๆสักเท่าไหร่ แต่มันได้ concept ครับ ลองคิดดูแบบง่ายๆ แทนที่จะต้องเขียน Framework ตัวใหญ่ๆ ถ้าหากเราสามารถแบ่ง Framework ออกเป็นส่วนๆ แล้วค่อยๆเรียกใช้งานเท่าที่จำเป็น เราก็ไม่จำเป็นต้อง load JavaScript ตัวใหญ่ๆทีเดียวแบบเมื่อก่อนแล้วครับ และยังช่วยให้เรา extend ความสามารถเพิ่มเติมต่อไปได้ง่ายอีกด้วยครับ เพราะมีการแยก module ออกจากกันอย่างชัดเจน ช่วยให้เราทำงานง่ายขึ้น และก็แก้ไขก็ง่ายดีด้วยครับ

ที่จริงแล้วเทคนิคนี้มันมีชื่อเรียก ชื่ออย่างเป็นทางการมันเรียกว่า Modular Pattern เป็น Best Practice รปแบบหนึ่ง ซึ่งผมเห็นว่ามันมีประโยชน์ดี แล้วสามารถนำไปใช้งานได้จริงครับ ก็คิดว่าบทความนี้น่าจะพอจุดประกายให้ใครอีกหลายคนนำไปประยุกต์ใช้งานกันต่อไปนะครับ หากนำไปใช้งานแล้วได้ผลดี ก็อาจช่วยเขียนบทความเป็นวิทยาทานให้คนอื่นๆต่อไปแล้วกันนะครับ
  
แหล่งที่มา : http://requirejs.org

1 comment:

  1. ขอบคุณมากครับสำหรับบทความ กำลังจะลองเล่นดู งงๆ

    ReplyDelete