9 Lỗi thường gặp khi lập trình Ionic

Giới thiệu

Ionic, được ra mắt hai năm trước, là một bộ công cụ tuyệt vời dùng cho phát triển hybrid application (ứng dụng lai) dựa trên AngularJS. Ionic hiện đang rất phổ biến với kho ứng dụng lên đến con số hàng triệu cùng một cộng đồng mạnh mẽ với hàng nghìn developer.

Ionic không phải là mới. Trong khi đó, công nghệ web cùng các công cụ tối ưu lại đang thay đổi chóng mặt hằng ngày. Vì vậy, không dễ quyết định hướng đi cho một dự án mới. Trong điều kiện như vậy, developer có thể phạm lỗi và ảnh hưởng đến chất lượng của ứng dụng hoặc hiệu suất của team.

Hy vọng với những lỗi thường gặp dưới đây, các bạn sẽ có thể tránh được các vấn đề cơ bản, đồng thời gia tăng hiệu suất và quy mô ứng dụng khi sử dụng Ionic.

Ionic đang rất được ưa chuộng với hơn một triệu ứng dụng

Lỗi thường thấy #1: Quên kích hoạt Native Scrolling

Native Scrolling Cho phép Ionic nhận dạng sự kiện cuộn trên các webview được hỗ trợ. Ta có thể tạo Pull to Refresh (Kéo để làm mới), List Reordering (Sắp xếp lại danh sách)Infinite Scroll (cuộn vĩnh viễn) mà không cần JavaScript scrolling (ta chỉ cần JavaScript scrolling khi trình duyệt thiếu scroll event chuẩn).

Trên android, kể thừ phiên bản Ionic 1.2 (tháng 12, 2015), native scrolling được mặc định kích hoạt. Native scrolling đã cải thiện đáng kể hiệu suất và UX, giúp scroll mượt hơn nhờ asynchronous event.

Tiếc thay, do thiếu event chuẩn, nên native scrolling vẫn chưa được hỗ trợ trên nền tảng iOS.

Nếu bạn đang dùng phiên bản trước 1.2, bạn có thể bật Native Scrolling trên Android bằng cách dùng $ionicConfigProvider

Bạn cũng có thể bật và tắt Native scrolling trên mọi trang bằng cách sử dụng overflow-scroll điều hướng mọi ion-content:

Nên nhớ, không may là collection-repeat (cho phép ứng dụng hiện danh sách với nhiều đề mục) vẫn chưa được native scrolling hỗ trợ.

Lỗi thường thấy #2: Không dùng Ionic CLI để cài đặt Platform và Plugin

Ionic CLI thêm nhiều tính tính năng hay vào Cordova CLI. Plafrorm và plugin persistence là một trong các tính năng đó.

Tuy nhiên, với Cordova CLI, platform và plugin của bạn chỉ được cài đặt trên hệ thống riêng thôi. Và khi làm việc nhóm, bạn sẽ muốn chia sẻ môi trường, platform và plugin để tránh bug. Cũng với Cordova CLI, ta khó có thể đồng bộ dự án giữa nhều hệ thống. Tất nhiên, bạn cũng có thể commit các thư mục platform và plugin, nhưng chúng tôi không khuyên dùng cách này.

Khi dùng Ionic CLI để cài đặt platform ionic platform add ios và plugin ionic plugin add camera, file package.json sẽ được edit đúng cách.

Platform và plugin được lưu trữ trong thuộc tính cordovaPlatformscordovaPlugins:

Giờ đây, các developer khác đã đồng bộ dễ dàng hơn khi tạo code mới, đơn giản chỉ việc chạy ionic state restore khi cần thiết (thêm, xóa hoặc up phiên bản)

Lỗi thường thấy #3: Thinking Performance Comes out of the Box

Ionic được dựa trên AngularJS, và hiệu suất trên thiết bị vẫn chưa rõ. Về điểm này, tôi cam đoan với các bạn: chỉ với một ít kiến thức AngularJS thôi, các bạn có thể xây dựng một ứng dụng tầm cỡ với Ionic.

Một ví dụ điển hình là Sworkit app (được xây dựng với Ionic) với hơn 9 triệu người dùng, 7 triệu lượt tải và 4,5 sao trên Google Play.

Nếu muốn tận dụng tối đa AngularJS, bạn cần biết một số điều dưới đây trước khi bắt đầu dự án.

$watch

Với scope change trong AngularJS, nhìn chung có 4 kiểu $watch: $watch (normal), $watch (deep), $watchCollection$watchGroup.

Mỗi kiểu đều khác nhau, và chọn kiểu phù hợp có thể thay đổi hiệu suất đáng kể.

$watch (normal)

Sử dụng $watch normal sẽ chỉ kiểm tra thuộc tích Object hiện có, hoặc các Array item. Những thay đổi nông (như thêm thuộc tính Object hay nhét một item với vào một Array) sẽ không được hỗ trợ.

$watch (deep)

$watch deep sẽ thực hiện các thay đổi nông và sâu, như chức năng Nested Object. Với $watch deep, bạn chắc chắn sẽ không bỏ lỡ bất cứ thay đổi nào. Tuy vậy, hãy sử dụng cẩn trọng vì $watch deep có thể thay đổi hiệu suất.

$watchCollection

Có thể cân nhắc dùng $watchCollection giữa $watch normal$watch deep. $watchCollection cũng có thể so sánh object reference, và còn có thể shallow watches các thuộc tính của object bằng cách thêm thuộc tính Object hoặc đẩy item mới vào Array.

$watchGroup

Được giới thiệu ở AngularJS 1.3, $watchGroup cho phép theo dõi nhiều expression cùng một lúc.

Tuy  không thể cải thiện hiệu suất ứng dụng như với $watch normal, nhưng $watchGroup có thể theo dõi tổng hợp nhiều scopre expression.

Track By

track by được dùng để tránh các thao tác DOM dư thừa khi dùng ng-repeat. Nếu digest cycle tìm được ít nhất một phần tử thay đổi trong collection, ng-repeat sẽ render lại mọi phần tử. Vì thao tác DOM luôn ảnh hưởng đến hiệu suất ứng dụng, nên ta càng hạn chế càng tốt.

track by có thể xem là một bộ lọc đặc biệt, cho phép ta cập nhật các phần tử cần thiết chứ không cần phải render lại cả collection.

Chỉ cần nhớ, tránh dùng track by trên collection-repeat.

One-Time Binding

One-time binding (hoặc ::) được giới thiệu từ Angular 1.3, đã cải thiện đáng kể hiệu suất ứng dụng.

Về cơ bản, sử dụng one-time binding :: lên một expression sẽ loại expression đó khỏi danh sách $watchers khi quá tải. Đồng nghĩa với việc expression không thể cập nhật ngay cả khi dữ liệu thay đổi.

Lời khuyên của chúng tôi là hãy kiểm tra ứng dụng xem thử phần nào cập nhật được, phần nào không cập nhật được, và dùng one-time binding :: đúng theo đó. Khâu này sẽ giảm thiểu rất nhiều gánh nặng lên digest cycle.

Nên nhớ, one-time binding không thể được dùng trong collection-repeat, bởi vì list item trên màn hình sẽ thay đổi khi cuộn.

Và nếu bạn muốn tìm hiểu thêm về AngularJS và Ionic, tôi nghĩ các bạn nên đọc bài này Ultimate AngularJS and Ionic performance cheat sheet .

Lỗi thường thấy #4: Nhận thức logic View Cache còn mơ hồ

Ứng dụng trang sẽ không mặc định cache trang. Vì vậy khi sử dụng AngularJS, chắc hẳn bạn đã gặp cảnh trạng thái cuộn và trỏ nhập liệu không được lưu lại khi bạn duyệt tới hay lùi giữa các trang.

Với Ionic, mười trang sẽ được cache lại theo mặc định, và bạn có thể thay đổi tính năng này trên toàn hệ thống hoặc trên mỗi platform.

Dù cache trang có thể hơi khó hiểu với người mới một chút nhưng đây vẫn là một tính năng rất hay.

Vấn đề là nếu người dùng quay lại trang đã cache, controller sẽ không được tái khởi tạo như ở các ứng dụng AngularJS.

Với điều kiện như thế này, các bạn sẽ cập nhật dữ liệu trên trang như thế nào?

Giới thiệu các event vòng đời của controller

So với AngularJS, Ionic đưa ra nhiều event vòng đời hơn:

Những sự kiện này rất cần thiết nếu bạn muốn kiểm soát view cache.

Ví dụ như event $ionicView.loaded sẽ được kích hoạt ngay khi view được load. Nếu view này được cache, event này sẽ không được kích hoạt nữa, ngay cả khi người dùng quay lại. Đây thường là event bạn sẽ dùng để khởi động biến như event $viewContentLoaded trong AngularJS.

Nếu bạn muốn fetch dữ liệu mỗi khi truy cập view (được cache hoặc không), bạn có thể dùng event $ionicView.enter.

Khi dùng đúng event vào đúng lúc, bạn có thể cải thiện độ tiện dụng của ứng dụng.

Về phần hiệu suất, dùng cache view chỉ ảnh hưởng lên kích thước của DOM thôi. Khi trang được cache, mọi người xem sẽ bị ngắt kết nối và trang sẽ chuyển vào DOM để đợi được sử dụng lại.

Tuy kích thước của DOM sẽ ảnh hưởng đáng kể đến hiệu suất, nhưng cache mười trang vẫn chấp nhận được (dĩ nhiên còn phụ thuộc vào nội dung load của trang).

Lỗi thường gặp #5: Không biết về Crosswalk cho Android

Mỗi phiên bản Android chay một WebView (trình duyệt chạy ứng dụng) khác nhau. Hiệu suất sẽ khác với mỗi thiết bị, và đặc biệt tệ trên thiết bị Android đời cũ. Bạn có thể cài đặt Crosswalk để có trải nghiệm mượt mà như nhau trên mọi thiết bị Android. Crosswalk sẽ thêm trình duyệt Chromium mới nhất vào ứng dụng của bạn (20Mb mỗi APK, cả với ARM và X86).

Crosswalk có thể được cài đặt chỉ bằng cách dùng Ionic CLI hoặc Cordova CLI:

Lỗi thường gặp #6: Cố gắng chạy Cordova Plugin trong trình duyệt

Đa số developer dùng Ionic sẽ muốn ứng dụng của mình chạy trên iOS và Andoid. Sau khi thêm platform ionic platform add ios android và vài plugin ionic plugin add cordova-plugin-device-orientation cordova-plugin-contacts, nhiều người nghĩ họ có thể test trên trình duyệt được, đây là một lỗi sơ đẳng bởi không phải trình duyệt nào cũng có thể áp dụng cách này.

Plugin của Cordova được thiết kế để giao tiếp với thiết bị API native thông qua JavaScript. Plugin giao tiếp hoặc plugin định hướng thiết bị vì thế sẽ chỉ làm việc trên một thiệt bị.

Tuy nhiên, bạn có thể dễ dàng test code trên thiết bị và gỡ lỗi từ xa bằng máy tính.

Gỡ lỗi từ xa trên Android

Kết nối thiết bị, hãy chắc chắn rằng thiết bị được máy tính nhận biết bằng lệnh adb devices (bạn cần có Android SDK).

Build app và cài đặt vào thiết bị bằng lệnh ionic run android. Khi thiết bị khởi động ứng dụng, dùng Chrome dev tools mở console (trên máy tính) chrome://inspect/#devices, và kiểm tra thiết bị.

Gỡ lỗi từ xa trên iOS

Kết nối thiết bị, hãy chắc chắn rằng thiết bị được máy tính nhận biết. Build app và cài đặt vào thiết bị bằng lệnh ionic run ios –device.

Khi ứng dụng đã được khởi động, click vào Develop > Your iPhone > Your app để mở Safari dev tools (trên máy tính) :

Chạy Cordova Plugin trong trình duyệt

Chạy Cordova plugin trong trình duyệt là một chức năng cao cấp mà bạn nên biết. Từ Ionic 1.2, trình duyệt dã được hỗ trợ chính thức, mở ra kỷ nguyên ứng dụng cross-platform vượt ra khỏi iOS và Android.

Với Cordova Browser platform, Electron và công nghệ Web (JavaScript, HTML, và CSS) thôi, ta giờ đây đã có thể build ứng dụng Ionic cho trinhd duyệt và desktop (Windows, Linux và OSX)

Bạn có thể tìm starter kit trên Github.

Ứng dụng của bạn cần phải được biên soạn lại trước khi sử dụng được đúng như trên iOS hoặc Andoid:

Lệnh này sẽ biện soạn ứng dụng và mở trình duyệt mặc định.

Cross-platform plugin

Nhiều plugin như: Network, Camera và Facebook có hỗ trợ cùng lúc iOS, Android, và platform Browser cùng một lúc – tất cả với cùng API.

Bạn có thể biết được liệu thiết bị đang online hay offline trên mọi platform (iOS, Android, Trình duyệt và Desktop) bằng cách sử dụng ngCordova API:

Giờ đây, chắc hẳn bạn đã nghĩ đến việc tạo ra các sản phẩm chạy được ở bất cứ đâu chỉ với một dòng code base.

Lỗi thường thấy #7: Đi theo cấu trúc Starter Kit với các ứng dụng quy mô lớn

Khi dùng lệnh ionic start myapp, một dự án mới tạo sẽ đi theo cấu trúc folder sau:

Đây được gọi là cấu trúc Folder-by-Type. Với cấu trúc này, các file JavaScript, CSS, và HTML sẽ được nhóm theo kiểu. Cấu trúc này trông có vẻ dễ cho người mới, nhưng bạn sẽ sớm mất kiểm soát khi quy mô quá lớn.

Một vài lý do không nên dùng cấu trúc Folder-by-Type:

  • Số file trong folder có thể trở nên quá lớn
  • Với một tính năng cụ thể. sẽ khó tìm tất cả các file mà bạn cần điều chỉnh
  • Làm việc với một tính năng sẽ dẫn đến quá nhiều folder mở
  • Ứng dụng càng lớn, càng khó làm việc

Với ứng dụng quy mô lớn, tôi khuyên dùng cấu trúc Folders-by-Feature, các file JavaScript, CSS, và HTML lúc này sẽ được nhóm theo tính năng hoặc module AngularJS:

Lý do nên dùng cấu trúc Folder-by-Feature:

  • Số file trong folder bị giới hạn ít đi
  • Dễ tìm tất cả các file khi cần điều chỉnh một tính năng (vì ở cùng một folder)
  • Bạn có thể làm việc độc lập với một tính năng
  • Dễ biết được module thể hiện gì (chỉ cần biết tên folder là đủ)
  • Dễ tạo tính năng mới, chỉ cần copy/paste một tính năng sẵn có là xong

Cấu trúc này gần giống với cấu trúc Folders-by-Component được mặc định trong các ứng dụng Angular2/Ionic2.

Lỗi thường thấy #8: Ràng buộc với event, và quên mất requestAnimationFrame

Lỗi này có lẽ là lỗi gây ảnh hưởng mạnh nhất lên hiệu suất, và thường chỉ thấy ở người mới. Xem thử:

Mặc dù Ionic có kiểm soát các hành động này, quá trình có thể sẽ vẫn quá chậm. Nhìn chung, bất cứ thứ gì kích hoạt digest loop nên được hoãn lại, và không nên kích hoạt cùng lúc với hình ảnh nặng (cũng chính là kết quả của scrolling).

Thay vì ràng buộc với scroll event, và đặc biệt là animation, developer có thể sử dụng các phương pháp khác. Như requestAnimationFrame.

Đoạn code trên chỉ là một ví dụ đơn giản. Đoạn code kiểm tra xem thử người dùng có cuộn qua phần đầu phần tử chưa. Nếu bạn muốn áp dụng ví dụ này, hãy nhớ thêm lựa chọn thay thế vendor-specific để đảm bảo tương tích trên nhiều trình duyệt. Tùy vào trình duyệt, ứng dụng nhìn chung có thể chạy ở tốc độ tối ưu 60FPS hoặc đúng bằng độ làm tươi của màn hình.

Bạn cũng có thể muốn tìm hiểu thêm element.getBoundingClientRect(), có thể cung cấp thông tin về kích thước và vị trí của node HTML.

Lỗi thường thấy #9: Sao mẫu ứng dụng Ionic bằng tay

Ionic có thiết kế rất đặc thù (gần như hoàn toàn là ngôn ngữ hình ảnh). Đặc biệt với các sản phẩm nguyên mẫu và trong giai đoạn đầu, ta có thể tiếp kiệm được nhiều thời gian và chi phí bằng cách tận dụng các thành phần (component) và style phù hợp. Chúng khá chi tiết và mang tính thẫm mỹ cao.

Việc giới thiệu khung dây (wireframe) và mô hình giả lập (mockup) đã trở thành chuẩn của ngành. Thực sự trải nghiệm ứng dụng sẽ rất khác với chỉ được nhìn một tấm ảnh. Nhiều designer, và cả UX developẻ, đang sử dùng các công cụ như Axure hoặc Balsamiq cho phép nhanh chóng tạo khung dây (với ít ỏi chức năng).

Giờ đây, nhà phát triển Ionic cũng đã ra mắt một công cụ tương tự mang tên Ionic Creator dành riếng cho Ionic developers. Cong cụ có giao diện web kéo thả, và hỗ trợ gần như toàn bộ các chứng năng cốt lõi của Ionic. Công cụ này ưu việt ở chỗ nó có thể xuất mẫu theo nhiều format, với code Ionic chạy được, bạn thậm chí có thể build và share ứng dụng nữa. Ứng dụng có phần thu phí (nhưng bạn vẫn có thể sử dụng nhiều tính năng miễn phí).

Lời kết

Ionic đã cách mạng cả nền công nghiệp ứng dụng lai theo một cách không tưởng. Tuy vậy, thời gian qua, các phương thức cùng công cụ lại thiếu sự đột phá. Và hậu quả là, developer lại càng gặp phải nhiều sai lầm hơn.

Các chuyên gia trên Ionic luôn có cách phát triển các ứng dụng tầm cỡ song song trên nhiều platform. Cách này yêu cầu bạn phải tận dụng các công cụ sẵn có, tối ưu tiên hiệu suất, và đi theo các phương pháp tốt nhất.

Xin chân thành cảm ơn cộng đồng Ionic tuyệt với, gồm  Michał Mikołajczyk, Mike Hartington (Ionic Core team) và Katie Ginder-Vogel (Marketing & Communications Manager, Ionic), đã tạo điều kiện giúp tôi làm nên bài viết này.

ITZone via toptal

Chia sẻ bài viết ngay