Introduction to AMD Modules - Giới thiệu về module AMD (Asynchronous Module Definition)
Dojo hỗ trợ việc viết các modules bằng cú pháp khai báo bất đồng bộ Module (Asynchronous Module Definition), điều này giúp mã nguồn dễ viết và dễ bắt lỗi hơn. Trong bài hướng dẫn này, chúng tôi sẽ trình bày những kiến thức cơ bản và cách dùng AMD.
Nếu đã học Dojo và bắt đầu chuyển sang phiên bản 1.7, bạn cần tìm bản 1.8 và các hướng dẫn để chuyển từ module cũ sang AMD. Bài viết này chỉ tập trung kỹ về AMD.
Overview - Tổng quan
Cú pháp AMD là một cú pháp Dojo đề nghị khi bắt đầu học Dojo 1.7 . Nó cung cấp rất nhiều cải tiến từ Module Dojo ban đầu, bao gồm đầy đủ hệ thống bất đồng bộ, các gói di động, quản lý tốt hơn, và cải thiện việc hỗ trợ gỡ lỗi. Nó cũng là một định hướng cộng đồng tiêu chuẩn, nghĩa là các module ghi vào đặc tính kỹ thuật AMD có thể được sử dụng với bất kỳ loader (từ đoạn này trở đi chúng tôi xin phép gọi loader là trình tải) hoặc thư viện AMD tương thích. Trong bài này, chúng tôi sẽ giải thích về AMD và trình bày với bạn cách để dùng nó.
What is a module? - Module là gì ?
Một module là một giá trị có thể truy cập bởi một tham chiếu duy nhất. Nếu bạn có nhiều phần dữ liệu hoặc hàm mà bạn muốn sử dụng trong module, chúng phải có các thuộc tính trong một đối tượng duy nhất-đại diện cho module (dịch chỗ này hơi khó hiểu, tóm lại, mỗi module thì phải có tên duy nhất, mỗi thuộc tính và hàm trong nó cũng duy nhất, cái này chắc ai cũng biết). Thực tế mà nói, thật cần thiết để tạo một module với giá trị đơn giản <var tinnyModule = 'simple Value'>, nhưng nó đã là một module rồi đấy. Module bắt đầu có ý nghĩa nhiều hơn trong quá trình module hóa của bạn-tách ra thành những tập con để xử lý một chức năng lớn. Nếu bạn muốn đại diện cho một người với các thông tin như tên, địa chỉ, và cả các phương thức nữa. Tất cả các thông tin đó đều được đặt tại một vị trí mã duy nhất. Một module được lưu trữ trong hệ thống của bạn như một tập tin duy nhất
How do I create a module? - Làm sao để tạo một module ?
Cùng với AMD, bạn tạo một module bởi việc đăng ký nó với một trình tải.
Nói ngắn gọn trình tải là một đoạn code Javascript (đúng vậy, nó chỉ là Javascript) xử lý việc khai báo và tải các module. Khi bạn tải <dojo.js> hoặc <require.js>, bạn đã gọi một trình tải AMD. Trình tải khai báo các hàm để tương tác với nó (define, require,...)
Hàm toàn cục <define> cho phép bạn đăng ký một module cùng với trình tải. Đây là vài ví dụ:
define(5);Không quá phức tạp nhưng bạn đã đăng ký một module rồi đấy, và giá trị của nó là 5
define ({Khi module này được tải, chúng ta có 2 thuộc tính
thuVien: 'dojo'
phienBan: 1.10
})
define(function(){Trong trường hợp này, chúng ta đã tạo một hàm nhờ <define>. Hàm này được đánh giá và giá trị của nó được lưu lại bởi trình tải như là một module. Đoạn mã được đóng trong {} để tạo nên giá trị cục bộ (không thể được truy cập từ bên ngoài). Tuy nhiên ta vẫn có thể khảo sát và tính toán các biến này nhờ vào các phương thức được cung cấp trên đối tượng được trả về giống như là giá trị của module.
var giaTriCucBo = 0;
return {
tang: function() {
giaTriCucBo++;
}
giam: function() {
giaTriCucBo--;
}
layGiaTri: function(){
return giaTriCucBo;
}
};
});
How do I load a module? - Làm thế nào để tải một Module ?
Đối với người mới bắt đầu, chúng ta cần hiểu cách module được định nghĩa. Để tải module, bạn cần một vài cách định nghĩa chúng. Tương tự như hệ thống module/package của các ngôn ngữ lập trình khác, một AMD module được xác định bởi đường dẫn và tên file của chúng. Hãy lưu đoạn mã ở ví dụ trên vào trong một thư mục
app/dem.js (dem.js chứa nội dung là ví dụ lúc nãy)
Đồng thời thêm một trình tải (tất nhiên là của Dojo) và một tệp index.html - điểm bắt đầu ứng dụng của bạn. Điều này cho chúng ta biết cấu trúc của một file
/
index.html
/dojo/
/app/
dem.js
Trang index sẽ trông giống như thế này
<html> <body> <script src="dojo/dojo.js" data-dojo-config="async: true"></script> <script> require([ "app/dem" ], function(dem){ log(dem.layGiaTri()); dem.tang(); log(dem.layGiaTri()); dem.giam(); log(dem.layGiaTri()); }); </script> </body> </html>
(chi chú: " = " )
Xem lại điều gì đang xảy ra ở đây:
1. Trong <app/dem.js>, chúng ta gọi <define> để đăng ký một module cùng với trình tải. Chú ý là module của chúng ta tạo ra chỉ tham chiếu tới một đối tượng, không phải là một cấu trúc hàm - nghĩa là với tất cả bit của mã nạp module này sẽ nhận được một tham chiếu chính xác đến đối tượng như thế. Nói chung các module đều trả về các cấu trúc, nhưng trong vài trường hợp, nó được dành riêng cho việc chỉ để trả về một đối tượng đơn lẻ.
2.Bằng cách định vị module của chúng ta trong hệ thống tập tin, trong thư mục con, bên dưới thư mục chứa <index.html> và trong thư mục "anh em" (cùng cấp) của trình tải AMD (<dojo/dojo.js>), chúng ta không phải cấu hình thêm để trình tải biết rằng định danh module <app/dem> tải tệp <app/dem.js> và dùng nó để trả giá trị của module.
3.Trong tệp index.html, chúng ta gọi <require> để tải module <app/dem>. Bạn có thể tải module đơn giản bằng <require(["app/dem"])>. Nếu mã trong module có tác dụng khác(như tác động tới các module khác), bạn có thể không cần tham chiếu tới module ở mọi nơi. Tuy nhiên, nếu cần tham chiếu tới module, bạn cần một hàm callback. Trình tải sẽ chắc chắn rằng module của bạn đã được tải và một khi nó có module đó, nó sẽ gọi hàm callback để truyền từng module vào như là một tham số của hàm. Như bất cứ các hàm khác, bạn tự do trong việc đặt tên cho bất cứ tham số nào bạn muốn (không yêu cầu tên tham số liên quan đến tên module). Điều đó cũng có nghĩa là cần phải thực hành tốt để sử dụng tên giống với tên module.
Modules Loading Modules - Module tải Module
Các ví dụ trên đã cho thấy thật đơn giản để sữ dụng hàm <define>. Khi một ứng dụng đã được tổ chức tốt, nghĩa là các giữa các module có mối quan hệ rất tự nhiên. Hàm <define> có thể tự động tải các phần phụ thuộc vào hàm của bạn. Danh sách phụ thuộc được thông qua nhờ <define> trước giá trị module.
define([ "dojo/_base/declare", "dojo/dom", "app/dateFormatter" ], function(declare, dom, dateFormatter){ return declare(null, { showDate: function(id, date){ dom.byId(id).innerHTML = dateFormatter.format(date); } }); });
Ví dụ này chứng minh một vài thuộc tính điển hình của ứng dụng AMD:
1. Nhiều sự phụ thuộc - cả hai module "dojo/dom" và "app/dateFormatter"(giả sử là có module này với chức năng định dạng hiển thị ngày tháng) được xác định trong danh sách phụ thuộc.
2. Trả về một cấu trúc - một cái tên riêng biệt cho module như thế này sẽ là một cái gì đó giống như "app/DateManager"(ta hiểu rằng module này sẽ có chức năng xử lý ngày tháng và sẽ lưu vào tệp tin app/DateManager.js). Đoạn mã dưới đây sẽ giúp bạn hiểu rõ hơn:
require([
"app/DateManager"
], function(DateManager){
var dm = new DateManager();
dm.showDate('dateElementId', new Date());
});
Trong khi AMD là một trong những chủ đề đầu tiên bạn nên làm quen trước khi phát triển Dojo, thì <declare> (khai báo) là một hàm quan trọng khác - Nếu bạn chưa sẵn sàng quen với dojo/_base/declare , hãy đọc hướng dẫn này http://dojotoolkit.org/documentation/tutorials/1.10/declare/
Using pulgins - Dùng các plugin
Ngoài module bình thường, trình tải AMD cũng có một loại module mới gọi là plugin. Các plugin được dùng để mở rộng trình tải với các thuộc tính mới ngoài việc đơn giản là tải các module AMD. Các plugin được tải nhiều hay ít giống như các module bình thường nhưng dùng thêm một ký tự đặc biệt là dấu chấm than "!" ở cuối tên plugin. Dữ liệu sau dấu chấm than "!" được trực tiếp thông qua plugin để xử lý. Sẽ dễ hiểu hơn khi nhìn vào một số ví dụ. Dojo có một vài plugin mặc định, 4 plugin quan trọng nhất trong đó là: <dojo/text>, <dojo/i18n>, <dojo/has> và <dojo/domReady>. Hãy xem cách sử dụng chúng như thế nào:
dojo/text
<dojo/text> được dùng khi bạn cần tải một chuỗi từ file (như một mẫu HTML). Giá trị sẽ được lưu trữ (trong bộ đệm), để nếu có gọi lại các tệp đã lưu trữ thì không cần phải lấy lại từ máy chủ nữa. The builder(trình xây dựng) sẽ ghép các chuỗi được tải lên thành một hàng bằng <dojo/text>. Vì vậy, trong một số ví dụ, để tải một mẫu widget(tiện ích con, control con...), bạn sẽ phải khai báo module của mình như sau:
//trong "my/widget/NavBar.js"
define([
"dojo/_base/declare",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin",
"dojo/text!./templates/NavBar.html"
],function(declare,_WidgetBase,_TemplatedMixin,template){
return declare([_WidgetBase,_TemplatedMixin],{
//template chứa nội dung trong file "my/Widget/templates/NavBar.html"
templateString: template
});
});
dojo/i18n
<dojo/i18n> tải bộ tài nguyên ngôn ngữ tùy theo sự địa phương hóa trong mỗi trình duyệt web của bạn. Sử dụng như thế này:
// trong "my/widget/Dialog.js"Để hiểu thêm về <i18n>, mời bạn đọc bài internationalization tutorial ( http://dojotoolkit.org/documentation/tutorials/1.10/i18n/ )
define([
"dojo/_base/declare",
"dijit/Dialog",
"dojo/i18n!./nls/common"
],function(declare,Dialog,i18n){
return declare(Dialog,{
title: i18n.dialogTitle
})
});
dojo/has
Trình tải Dojo bao gồm một bản thực thi của <has.js> để phát hiện API; plugin <dojo/has> sẽ tăng khả năng yêu cầu module cho trình nạp một cách có điều kiện. Nó được dùng như sau:
// in "my/events.js"
define([
"dojo/dom",
"dojo/has!dom-addeventlistener?./events/w3c:./events/ie"
], function(dom, events){
// tham số events của hàm callback sẽ nạp từ module "my/events/w3c" nếu kiểm tra thấy có sử dụng API "dom-addeventlistener", nếu không thì sẽ là "my/events/ie"
events.addEvent(dom.byId("foo"), "click", function(){
console.log("Foo clicked!");
});
});
dojo/domReady
<dojo/domReady> được thay thế cho <dojo.ready>. Đơn giản, một module sẽ không được xử lý cho tới khi DOM đã sẵn sàng. Sử dụng:
// trong "my/app.js"Chú ý rằng chúng ta không thể khai một báo tham số trong hàm callback của mình để trả về bất kỳ giá trị nào của dojo/domReady. Đó là bởi vì nó trả về giá trị không phải là giá trị - chúng ta đơn giản chỉ dùng nó để hoãn lại việc gọi lại hàm callback. Yêu cầu các modules hoặc plugins với các giá trị không sử dụng có thể đặt ở phần cuối danh sách yêu cầu phụ thuộc, để sắp xếp các module và các biến cục bộ phụ thuộc một cách trật tự hơn.
define(["dojo/dom", "dojo/domReady!"], function(dom){
// hàm này sẽ không được thực thi cho đến khi DOM đã sẵn sàng
dom.byId("someElement");
});
Ngay cả khi không có dữ liệu nạp vào, thì dấu chấm than vẫn cần phải có. Nếu không có nó, bạn sẽ chỉ nạp module <dojo/domReady> như một module phụ thuộc thay vì kích hoạt tính năng đặc biệt của plugin.
Conclusion - Kết luận
Kiến thức căn bản về AMD cung cấp trong bài viết hướng dẫn này sẽ giúp bạn có những bước đầu trong hành trình phát triển với Dojo. Nhưng bạn sẽ sớm gặp những vấn đề phức tạp hơn. Hãy đọc bài Advanced AMD Usage ( http://dojotoolkit.org/documentation/tutorials/1.10/modules_advanced/ ) để giải quyết chúng:
* Cấu hình trình nạp để nó làm việc khi nạp và các packages ở những vị trí khác nhau, thậm chí ở những server khác nhau.
* Tạo các packages module di động (portble/tức là có thể xách đặt ở đâu cũng được--chứ không phải là riêng các gói cho mobile).
* Nạp nhiều phiên bản của module hoặc thư viện.
* Nạp mã non-AMD
Source - Nguồn
AMD Specification ( https://github.com/amdjs/amdjs-api/wiki/AMD )
Không có nhận xét nào:
Đăng nhận xét