Lập trình NodeJS và AngularJS

From CodeForLife
Jump to: navigation, search

Lập trình NodeJS

 

 

Lập trình Angular

Link học AngularJS:

Link học Angular:

So sánh AngularJS và Angular

Angular chia làm hai phiên bản chính:

  • AngularJS: Mọi người hay gọi là Angular 1 được tạo năm 2009. Phiên bản này đưa ra hai cách binding dữ liệu và cách thay đổi trong Javascript sẽ tự động được cập nhật lên giao diện người dùng. Hơn nữa AngularJS hỗ trợ directive cho phép tạo ra nhiều mã riêng và tái sử dụng mã. Nói chúng, nó giúp lập trình viên viết các ứng dụng theo mô hình MVC hoặc MVVM theo cách đơn giản hơn.
  • Angular: Dần dần ngày càng nhiều thứ được thêm vào core, vì thế Angular Team quyết định tạo ra một phiên bản hoàn toàn mới. Các bản Angular 2, 4, ... bây giờ đều gọi là Angular và các phiên bản mới bây giờ đều tương thích ngược với Angular 2.

Hiện tại Angular được sử dụng phổ biến hơn, có nhiều thư viện hỗ trợ hơn. Vì vậy trong hầu hết trường hợp thì Angular là lựa chọn tốt hơn.
Ngoài ra, trình duyệt hỗ trợ cũng là yếu tố quan trọng, nếu ứng dụng của bạn chỉ hỗ trợ trình duyệt mới thì Angular là lựa chọn tốt nhất nhưng nếu bạn muốn hỗ trợ IE8 thì AngularJS tốt hơn.

Dưới đây là một số sự khác nhau cơ bản giữa AngularJS và Angular:

  • LanguageAngular dựa trên TypeScript trong khi AngularJS dựa trên JavaScript. Typescript là một dự án mã nguồn mở được Microsoft phát triển, được xem là một phiên bản nâng cao của Javascript. Chi tiết về sự khác nhau xem địa chỉ: https://viblo.asia/p/gioi-thieu-typescript-su-khac-nhau-giua-typescript-va-javascript-LzD5dDn05jY
  • Controllers vs components: AngularJS sử dụng thuật ngữ scopecontroller. Bạn có thể thêm nhiều biến vào scope, các biến này sẽ được nhìn thấy trong View và Controller. AngularJS cũng đưa ra một khái niệm rootScope, các biến trong rootScope được sử dụng trong toàn bộ ứng dụng. Còn Angular không có khái niệm scopecontroller, mà nó sử dụng mô hình phân cấp các thành phần, cách tiếp cận giống ReactJS.
  • Template engine:
    • AngularJS sử dụng nhiều directive (chỉ thị) và nhà phát triển cũng có thể tạo ra các directive mới. Angular cũng có directive chuẩn, nhưng chúng được sử dụng theo cách khác. Ví dụ:
      • AngularJS:
        • ng-model sử dụng để tạo "two-way binding" (Binding hai chiều: Biến thay đổi thì cập nhật giao diện, trên giao diện thay đổi thì cập nhật biến)
        • ng-bind sử dụng để tạo "one-way binding" (Binding một chiều: Biến thay đổi thì cập nhật giao diện)
      • Angular chỉ sử dụng ngModel, những cách viết khác nhau:
        • Nếu bạn viết nó trong "[]" thì sẽ là one-way binding.
        • Nếu bạn viết nó trong "[()]" thì sẽ là two-way binding.
    • Chỉ thị ng-repeat trong AngularJS đổi thành ngFor trong Angular.
  • Các thay đổi khác: Angular là phiên bản mới hơn nên có nhiều lợi thế hơn như:
    • Mô đun hóa: Nhiều chức năng cốt lõi đã được chuyển sang các mô đun khác nhau. Giúp cho core nhanh hơn, tải động, biên dịch không đồng bộ và hỗ trợ reactive programming.
    • Angular Cli: Một gói giúp bạn dễ dàng tạo ra các project Angular. Chi tiết xem: https://cli.angular.io/
    • ...

Tham khảohttps://gorrion.io/blog/angularjs-vs-angular/

Cấu trúc thư mục chuẩn

Thực tế khi viết ứng dụng Angular, việc cấu trúc hóa thư mục trong project thế nào là tùy bạn. Nhưng tôi khuyên bạn hãy cấu trúc hóa thư mục theo một chuẩn nào đó để tiện cho việc coding, testing, bảo trì sau này.
Cấu trúc hóa thư mục theo chức năng được nhiều người sử dụng, bạn có thể tham khảo bài viết: AngularJS Best Practices: Directory Structure

Angular-folder-structure.PNG

Cấu trúc như sau:

  • index.html: Tệp chính load toàn bộ thư viện và các phần tử angular.
  • assets: Chứa toàn bộ tài sản (như ảnh, css, thư viện thêm...) cần cho ứng dụng nhưng không liên quan đến mã Angular của bạn.
  • app: Thư mục chính chứa mã nguồn ứng dụng
    • app.module.js: Tệp xử lý việc thiết lập ứng dụng.
    • app.route.js: Tệp xử lý việc thiết lập cấu hình định tuyến.
    • shared: Chứa các thành phần, tính năng sử dụng nhiều nơi trong ứng dụng, giống như các thành phần dùng chung.
    • components: Thư mục chứa các thành phần trong ứng dụng của bạn, mỗi trang ứng với một thư mục riêng, có thể chia nhỏ hơn nếu cần.

Một số "Best Practices" sử dụng trong nhiều ứng dụng:

  • Mô đun hóa phần Header và Footer: Nhiều ứng dụng tạo thư mục Core trong thư mục components, và trong thư mục này tạo hai thư mục con là Header và Footer. Hai thành phần này được sử dụng ở nhiều trang.
  • Mô đun hóa phần Route: Với ứng dụng rất lớn, bạn có thể tách Route thành nhiều Route con. Ví dụ bạn có thể tạo thêm tệp blogRoutes.js chỉ chứa route liên quan tới blog.
  • Đừng quên rút gọn mã: Khi triển khai trên môi trường thật, bạn phải rút mã trước khi triển khai. Điều này giúp bạn phần nào giấu code và giảm tải lần đầu cho ứng dụng của bạn. Có nhiều thành phần mở rộng giúp bạn làm điều này như Grunt Gulp

Coding style

Thông thường khi coding một ngôn ngữ phải tuân theo coding chuẩn để tiện cho việc người khác đọc hiểu và bảo trì sau này.
Mình xin đề xuất tuân theo chuẩn như dưới:

 

Theme cho ứng dụng

Khi tạo ứng dụng web, bạn nên lựa chọn theme trước. Sau đó tích hợp theme này vào Angular hoặc AngularJS.

Nhiều theme miễn phí cũng khá đẹp để bạn lựa chọn:

Một số theme tôi hay sử dụng:

Với các theme trên thường bạn phải thêm một bước để tích hợp vào Angular hoặc AngularJS.

Ngoài ra Angular có free template tại địa chỉ: CoreUI Free Angular 2+ Admin Template
Template này đã tích hợp sãn Angular 2+, lệnh sau để tải và cài đặt template (Các lệnh này như các lệnh làm việc với Angular 2+):
git clone https://github.com/coreui/coreui-free-angular-admin-template.git my-project
cd my-project
npm install

Lệnh sử dụng:
ng serve
ng build

[NodeJS] Một số tác vụ đặc biệt

Vấn đề Memory Leak trong NodeJS

Tham khảo:

Tạo heapdump để kiểm tra memory

Sử dụng thư viện heapdump để tạo dữ liệu: https://www.npmjs.com/package/heapdump

var heapdump = require('heapdump');
function writeHeadDump() {
	heapdump.writeSnapshot('./heapdump/heapdump_' + Date.now() + '.heapsnapshot');
}

function cleanHeap() {
	// 1. Force garbage collection every time this function is called
	try {
		global.gc();
	} catch (e) {
		console.log("You must run program with 'node --expose-gc index.js' or 'npm start'");
		process.exit();
	}
	 
	// 2. Output Heap stats
	var heapUsed = process.memoryUsage().heapUsed;
	console.log("Program is using " + heapUsed + " bytes of Heap.");
}

// In dau tien o 5 phut dau tien
setTimeout(function() {
	writeHeadDump();
}, 300000);

// 1h in mot lan
setInterval(function () {
	cleanHeap();
	setTimeout(writeHeadDump, 5*1000);
}, 3600*1000);

Để hàm cleanHeap chạy được khi start ứng dụng cần tham số "--expose-gc"

Memory tăng liên tục khi sử dụng MySQL Pool

Tôi gặp trường hợp sử dụng MySQL Pool từ thư viện: https://www.npmjs.com/package/mysql
Khi truy vấn database liên tục (Giao dịch nhiều), RAM của ứng dụng tăng nhanh và không bao giờ giảm, tức không bao giờ được giải phóng. Tương tự như báo lỗi tại link: https://github.com/mysqljs/mysql/issues/697

Nguyên nhân: Do Connection chưa hủy, nên nó cứ giữ các biến cache lại nhiều, và không thể giải phóng được.
Giải pháp: Hàng ngày vào giờ bảo gì phải tự động destroy các connection.

[AngularJS] Một số tác vụ đặc biệt

Website hỗ trợ nhiều ngôn ngữ

 

Sử dụng timer

Trong AngularJS bạn có thể sử dụng hàm setTimeout setInterval của Javascript để tạo timer, nhưng để đảm bảo việc TạoXóa timer đúng như mong muốn, bạn nên sử dụng qua biến $interval của AngularJS như dưới:

var timer = null;
...
timer = $interval(function () {
    // Thực hiện xử lý ở đây
}, 1000);
$scope.$on('$destroy', function(){
    $interval.cancel(timer);
});

Lấy biến $rootScope, $scope từ console trình duyệt

Nhiều khi bạn muốn xem dữ liệu trong biến $rootScope của AngularJS từ trình duyệt, bạn sử dụng lệnh sau trên màn hình console của trình duyệt:
$rootScope = angular.element(document).scope();

Với biến $scope bạn đánh lệnh sau:
$scope = angular.element(document.getElementById('yourElementId')).scope();
Trường hợp này bạn biến element html tương ứng với scope.

Tự động thêm link vào URL trong một đoạn văn bản

Trong nhiều trường hợp, khi hiển thị text lên trình duyệt, bạn muốn tự động thêm thẻ link cho các URL có trong văn bản. Trong trường hợp này bạn có thể sử dụng thư viện anchorme: https://github.com/Jpja/CounterTools/tree/master/lib/anchorme

Các bước thực hiện:

  • B1: Tải tệp anchorme.min.js từ địa chỉ trên
  • B2: Include vào trong tệp html:
    <script src="anchorme.min.js"></script>
  • B3: Trong code javascript, gọi hàm anchorme.js là xong.
    • VD1: Tự động thêm link bình thường
      var someText = "this is a text with a link www.github.com ..";
      var result = anchorme.js(someText);
    • VD2: Thêm link với thuộc tính target=_blank để link được mở trong tab mới.
      var someText = "this is a text with a link www.github.com ..";
      var result = anchorme.js(someText, {"target":"_blank"});
    • VD3: Thêm link với nhiều lựa chọn hơn:
      var someText = "this is a text with a link www.github.com ..";
      var result = anchorme.js(someText, {"class":"someclassname","id":"someID","target":"_blank", "attribute-name":"attribute-property"});

Hiển thị HTML trong AngularJS

Bạn tham khảo link sau:

Các bước thực hiện:

  • B1: Cài đặt angular-sanitize bằng lệnh sau:
    npm install angular-sanitize 
  • B2: Trong tệp html include thư viện angular-sanitize. Ví dụ như sau:
    <script src="node_modules/angular-sanitize/angular-sanitize.min.js"></script>
  • B3: Include mô đun ngSanitize vào ứng dụng app. Ví dụ như dưới:
    var app = angular.module('myApp', ['ngSanitize']);
  • B4: Để tránh lỗi [$sce:unsafe], bạn thêm đoạn code sau vào ứng dụng apps:
    app.filter('to_trusted', ['$sce', function($sce){
        return function(text) {
            return $sce.trustAsHtml(text);
        };
    }]);
  • B5: Khi sử dụng bạn chỉ cần bind giá trị vào thuộc tính ng-bind-html của một thẻ html nào đó là được. Ví dụ:
     

Chú ý: Trong một số bản Angular mới, đôi khi không cần bước B1, B2 và B3.

Nén dữ liệu trả về

Việc nén dữ liệu trả về client sẽ giúp giảm thời gian dữ liệu truyền từ server về client, do đó làm tăng tốc độ ứng dụng web. Để giúp server hỗ trợ việc này, bạn thực hiện như sau:

  • Với Express 3, bạn thêm lệnh sau vào phần xử lý server:
    app.configure(function(){
        //....
        app.use(express.compress());
    });
  • Với Express 4+: Bạn cần cài đặt thêm gói riêng bằng lệnh sau:
    npm install compression
    Sau đó thêm code sau vào phần xử lý server:
    var compression = require('compression');
    app.use(compression());

 

 

[AngularJS] Một số lỗi hay gặp

UI không cập nhật khi biến $scope thay đổi (Angular $scope variable not updating)

Đôi khi bạn gặp trường hợp biến $scope đã cập nhật nhưng giao diện HTML chưa thấy cập nhât. Cái này đôi khi mình gặp, cũng không hiểu tại sao, nhưng mình tìm ra giải pháp ở hai link dưới:

Cách 1: Theo Link 2 các dữ liệu hiển thị ra UI bạn phải lưu vào trong Object. Vi dụ thay vị lưu trong:
$scope.primitiveVariale
Thì bạn lưu trong object:
$scope.data = { primitiveVariale:null }

Cách 2: Theo link 1, sau khi update biến $scope, bạn gọi thêm hàm $scope.$apply();. Ví dụ:
$scope.data = { ... };
$scope.$apply();

WebSocket is closed before the connection is established

Mô tả:
Khi sử dụng socket.io để trao đổi dữ liệu giữa client và server, trên màn hình Console của trình duyệt thấy báo lỗi "WebSocket is closed before the connection is established" và socket.io bị connect/disconnect liên tục.
Mình gặp lỗi này khi:

  • Khi truyền dữ liệu tương đối lớn. Nếu chỉ truyền dữ liệu với kích thước nhỏ thì có thể không bị lỗi này.
  • Đường mạng chậm: Đường mạng LAN thường không bị mà hay

Nguyên nhân:
Sau khi kiểm tra phát hiện nguyên nhân do sử dụng phiên bản socket.io giữa client và server lệch nhau. Server sử dụng bản 2.0.4 còn client sử dụng bản 1.4.5

Giải pháp:
Sử dụng cùng một phiên bản socket.io giữa client và server. Hiện tại tôi sử dụng phiên bản 2.0.4