Kata pengantar
AngularJS mudah dikembangkan, memiliki banyak fitur dan efek yang baik, menghasilkan lebih banyak aplikasi, dan beberapa perangkap disertai. Artikel ini mencantumkan beberapa masalah umum yang rentan terhadap masalah AngularJS. Mari kita lihat bersama.
1. Struktur Direktori MVC
AngularJS, menjadi tumpul, adalah kerangka kerja MVC. Modelnya tidak sepenuhnya didefinisikan seperti kerangka kerja backbone.js, tetapi arsitekturnya tepat. Saat Anda bekerja dalam kerangka kerja MVC, adalah umum untuk mengklasifikasikannya berdasarkan jenis file:
Templat/ _login.html _feed.htmlapp/ app.js pengontrol/ logincontroller.js feedcontroller.js arahan/ feedentrydirective.js layanan/ loginservice.js feedservice.js filter/ capatalizeFilter.jsservice.js
Tampaknya ini tampaknya merupakan struktur yang jelas, belum lagi bahwa rel melakukan hal yang sama. Namun, begitu aplikasi mulai berkembang, struktur ini akan menyebabkan Anda membuka banyak direktori sekaligus. Apakah Anda menggunakan Sublime, Visual Studio, atau VIM yang dikombinasikan dengan Nerd Tree, Anda akan menginvestasikan banyak waktu terus -menerus meluncur ke atas dan ke bawah di pohon direktori.
Tidak seperti membagi file berdasarkan jenis, sebaliknya, kita dapat membagi file dengan karakteristik:
app/ app.js feed/ _feed.html feedcontroller.js feedentrydirective.js feedservice.js login/ _login.html Logincontroller.js Loginservice.js Shared/ CapatalizeFilter.js
Struktur direktori ini memudahkan kita untuk menemukan semua file yang terkait dengan fitur, dan dengan demikian mempercepat kemajuan pengembangan kita. Meskipun mungkin kontroversial untuk menempatkan file .html dan .js di satu tempat, waktu yang dihemat lebih berharga.
2. Modul
Sangat umum untuk meletakkan semuanya di bawah modul utama. Untuk aplikasi kecil, tidak ada masalah di awal, tetapi Anda akan segera menemukan bahwa ada sesuatu yang curang.
var app = angular.module ('app', []); app.service ('myservice', function () {// kode layanan}); app.controller ('myctrl', function ($ scope, myService) {// kode controller});Setelah ini, strategi umum adalah untuk mengklasifikasikan objek dari jenis yang sama.
var services = angular.module ('services', []); services.service ('myservice', function () {// kode layanan}); pengontrol var = angular.module ('pengontrol', ['layanan']); controllers.controller ('myctrl', function ($ scope, myservice) {// controller code}); var app = angular.module ('app', ['controllers', 'services']);Metode ini mirip dengan struktur direktori yang disebutkan pada bagian pertama di atas: tidak cukup baik. Menurut filosofi yang sama, dapat diklasifikasikan berdasarkan karakteristik, yang mengarah pada skalabilitas.
var sharedservicesmodule = angular.module ('sharedservices', []); sharedservices.service ('networkservice', function ($ http) {}); var loginModule = angular.module ('login', ['sharedservices']); LoginModule.Service ('LogInservice', function (NetWorkService) {}); LOGINMODULE.Controller ('loginctrl', function ($ scope, logInservice) {}); var app = angular.module ('app', ['sharedservices', 'login']);Ketika kami mengembangkan aplikasi yang besar, mungkin bukan semuanya yang terkandung pada satu halaman. Menempatkan jenis fitur yang sama dalam satu modul membuatnya lebih mudah untuk menggunakan kembali modul di seluruh aplikasi.
3. Injeksi ketergantungan
Injeksi ketergantungan adalah salah satu pola terbaik di AngularJS, yang membuat pengujian lebih sederhana dan jelas tentang mengandalkan objek yang ditentukan. Metode injeksi AngularJS sangat fleksibel. Cara termudah adalah dengan hanya meneruskan nama ketergantungan ke function modul:
var app = angular.module ('app', []); app.controller ('mainctrl', function ($ scope, $ timeout) {$ timeout (function () {console.log ($ scope);}, 1000);}); Di sini, jelas bahwa MainCtrl tergantung pada $scope dan $timeout .
Semuanya indah sampai Anda siap untuk menggunakannya ke produksi dan ingin merampingkan kode Anda. Jika Anda menggunakan Uglifyjs, contoh sebelumnya akan menjadi seperti ini:
var app = angular.module ("app", []); app.controller ("mainctrl", function (e, t) {t (function () {console.log (e)}, 1e3)})Bagaimana AngularJ tahu siapa yang bergantung pada MainCtrl? AngularJS menyediakan solusi yang sangat sederhana, yaitu, melewati dependensi ke dalam array, elemen terakhir dari array adalah fungsi, dan semua dependensi digunakan sebagai parameternya.
app.controller ('mainctrl', ['$ scope', '$ timeout', function ($ scope, $ timeout) {$ timeout (function () {console.log ($ scope);}, 1000);}]);Melakukan hal itu akan membuat kode disederhanakan, dan AngularJS tahu bagaimana menafsirkan ketergantungan eksplisit ini:
app.controller ("mainctrl", ["$ scope", "$ timeout", function (e, t) {t (function () {console.log (e)}, 1e3)}]))3.1 Ketergantungan Global
Ini sering terjadi ketika menulis program AngularJS: Suatu objek memiliki ketergantungan, dan objek ini mengikat dirinya pada ruang lingkup global, yang berarti bahwa ketergantungan ini tersedia dalam kode AngularJS apa pun, tetapi ini menghancurkan model injeksi ketergantungan dan menyebabkan beberapa masalah, terutama selama proses pengujian.
Menggunakan AngularJS memudahkan untuk merangkum ketergantungan global ini ke dalam modul, sehingga mereka dapat disuntikkan seperti modul standar AngularJS.
Underscore.js adalah perpustakaan hebat yang menyederhanakan kode javascript dalam gaya fungsional, dan Anda dapat mengubahnya menjadi modul dengan cara berikut:
var underscore = angular.module ('underscore', []); underscore.factory ('_', function () {return window._; // Underscore harus sudah dimuat pada halaman}); var app = angular.module ('app', ['underscore']); app.controller ('mainctrl', ['$ scope', '_', function ($ scope, _) {init = function () {_.keys ($ scope);} init ();}]);Pendekatan ini memungkinkan aplikasi untuk terus berkembang dengan gaya injeksi ketergantungan AngularJS, dan juga dapat menukar garis bawah selama fase pengujian.
Ini mungkin tampak sepele dan tidak perlu, tetapi jika kode Anda menggunakan penggunaan ketat (dan harus digunakan), maka ini diperlukan.
Iv. Ekspansi pengontrol
Pengontrolnya adalah daging dan kentang AngularJS, dan jika Anda tidak hati -hati, Anda akan menambahkan terlalu banyak logika, terutama di awal. Pengontrol tidak boleh mengoperasikan DOM atau memegang pemilih DOM, di situlah kita perlu menggunakan instruksi dan model NG. Demikian pula, logika bisnis harus ada dalam layanan, bukan pengontrol.
Data juga harus disimpan dalam layanan kecuali mereka sudah terikat pada $ SCOPE. Layanan itu sendiri adalah singleton dan ada sepanjang kehidupan aplikasi, tetapi pengontrol bersifat sementara di antara keadaan aplikasi. Jika data disimpan dalam pengontrol, ketika dipakai lagi, ia perlu mendapatkan kembali data dari suatu tempat. Bahkan jika data disimpan di LocalStorage, kecepatan pencarian adalah urutan besarnya lebih lambat dari variabel JavaScript.
AngularJS bekerja dengan baik saat mengikuti Prinsip Tanggung Jawab Tunggal (SRP). Jika pengontrol adalah koordinator antara tampilan dan model, itu harus berisi logika sesedikit mungkin, yang juga akan memfasilitasi pengujian.
5. Layanan vs Pabrik
Hampir setiap pengembang AngularJS bermasalah dengan kata benda ini ketika dia pemula, yang benar -benar tidak pantas mendapatkannya, karena mereka hanya gula sintaksis untuk hal yang hampir sama!
Berikut adalah definisi mereka dalam kode sumber AngularJS:
factory factory (name, factoryfn) {return penyedia (name, {$ get: factoryfn}); } layanan fungsi (nama, konstruktor) {return factory (name, ['$ injector', function ($ injector) {return $ injector.instantiate (konstruktor);}]);} Dari kode sumber, Anda dapat melihat bahwa layanan hanya memanggil fungsi factory , dan yang terakhir memanggil fungsi provider . Faktanya, AngularJS juga menyediakan enkapsulasi provider tambahan untuk beberapa nilai, konstanta, dan dekorasi, yang tidak menyebabkan kebingungan yang sama, dan dokumasinya sangat jelas.
Karena layanan hanya memanggil fungsi factory , apa bedanya? Petunjuknya service di $injector $injector.instantiate .
Berikut adalah contoh yang menunjukkan bagaimana service dan factory melakukan hal yang sama:
var app = angular.module ('app', []); app.service ('HelloWorldService', function () {this.hello = function () {return "Hello world";};}); app.factory ('helloWorldfactory', function () {return {hello: function () {return "hello world";}}}); Ketika helloWorldService atau helloWorldFactory disuntikkan ke pengontrol, mereka semua memiliki metode Hello yang mengembalikan "Hello World". Konstruktor service ini dipakai sekali ketika dinyatakan, dan objek factory dilewati setiap kali disuntikkan, tetapi masih ada satu contoh factory . Semua providers adalah singleton.
Karena Anda dapat melakukan hal yang sama, mengapa Anda membutuhkan dua gaya berbeda? Dibandingkan dengan service , factory memberikan lebih banyak fleksibilitas karena dapat mengembalikan fungsi, yang dapat dibuat sesudahnya. Ini melayani konsep pola pabrik dalam pemrograman berorientasi objek, di mana pabrik dapat menjadi objek yang dapat membuat objek lain.
app.factory ('hellofactory', function () {return function (name) {this.name = name; this.hello = function () {return "hello" + this.name;};};};}); Berikut adalah contoh pengontrol, menggunakan service dan dua factory , helloFactory mengembalikan fungsi yang menetapkan nilai name ketika objek baru dibuat.
app.controller ('helloctrl', function ($ scope, helloworldservice, helloWorldfactory, hellofactory) {init = function () {helloWorldService.hello (); // 'hello world' helloworldfactory.hello (); // 'hello world' hello world 'helloworldfactory.hello (); //' hello world 'hell hellofactory (helloWorldfactory.hello (); / /' hello world 'hell hellofactory (helloWorldfactory.hello (); /' hello world 'hell hellofactory (helloWorldFactory. init ();});Saat Anda pemula, yang terbaik adalah hanya menggunakan layanan.
Factory juga berguna saat merancang kelas dengan banyak metode pribadi:
app.factory ('privateFactory', function () {var privateFunc = function (name) {return name.split (""). Reverse (). gabungkan (""); // membalikkan nama}; return {hello: name) {return "hello" + privateFunc (name);}};};}); Dengan contoh ini, kita dapat membuat metode privateFunc tidak dapat diakses oleh API Publik privateFactory . Pola ini dapat dilakukan dalam service , tetapi lebih mudah di factory .
6. Batarang tidak digunakan
Batarang adalah plugin krom yang sangat baik untuk mengembangkan dan menguji aplikasi AngularJS.
Batarang memberikan kemampuan untuk menelusuri model, yang memberi kita kemampuan untuk mengamati bagaimana AngularJS terikat pada ruang lingkup, yang sangat berguna saat menangani instruksi dan mengisolasi berbagai nilai terikat.
Batarang juga menyediakan grafik ketergantungan, yang berguna jika kita terpapar pada basis kode yang belum diuji, yang dapat menentukan layanan mana yang harus difokuskan.
Akhirnya, Batarang memberikan analisis kinerja. Angular dapat digunakan sebagai paket dan memiliki kinerja yang baik, tetapi terkadang tidak begitu mulus untuk aplikasi yang penuh dengan instruksi khusus dan logika yang kompleks. Menggunakan alat kinerja Batarang, Anda dapat secara langsung mengamati fungsi mana yang berjalan paling lama dalam siklus pencernaan. Alat kinerja juga dapat menampilkan pohon arloji lengkap, yang berguna ketika kami memiliki banyak pengamat.
7. Terlalu banyak pengamat
Pada titik sebelumnya, kami menyebutkan bahwa AngularJS dapat digunakan sebagai paket dan memiliki kinerja yang baik. Karena pemeriksaan data kotor perlu diselesaikan dalam satu siklus Digest, setelah jumlah pengamat tumbuh sekitar 2000, siklus ini akan menyebabkan masalah kinerja yang signifikan. (Angka 2000 tidak dapat dikatakan menyebabkan penurunan kinerja yang signifikan, tetapi ini adalah nilai empiris yang baik. Dalam versi rilis AngularJS 1.3, sudah ada beberapa perubahan yang memungkinkan kontrol ketat dari siklus pencernaan.)
"Ekspresi fungsi eksekusi langsung (IIFE)" berikut ini akan mencetak jumlah semua pengamat di halaman saat ini. Anda dapat menempelkannya ke dalam konsol dan mengamati hasilnya. IIFE ini berasal dari jawaban Jared di Stackoverflow:
(function () {var root = $ (document.geteLementsbyTagname ('body')); var watchers = []; var f = fungsi (element) {if (element.data (). hasownproperty ('$ scope') {angular.foreach (element.data (). $ scope. $$ function, function {{element.data (). $ scope. $$ function, function {) {{element.data (). $ scope. $$ function, function, function {) {{). angular.foreach (element.children (), function (childElement) {f ($ (childElement));});};Dengan cara ini, jumlah pengamat diperoleh, dikombinasikan dengan pohon arloji di bagian Kinerja Batarang, Anda harus melihat di mana kode duplikat ada, atau di mana data konstan ada dan juga memiliki jam tangan.
Ketika ada data yang tidak berubah dan Anda ingin menggunakan AngularJS untuk template, Anda dapat mempertimbangkan untuk menggunakan BindOnce. BindOnce adalah arahan sederhana yang memungkinkan Anda menggunakan template di AngularJS, tetapi tidak menambah arloji, yang memastikan bahwa jumlah jam tangan tidak akan tumbuh.
8. Kisaran terbatas $ SCOPE
Warisan berbasis prototipe JavaScript memiliki perbedaan halus dari pewarisan berbasis kelas dalam objek yang berorientasi objek, yang biasanya bukan masalah, tetapi kehalusan ini dimanifestasikan ketika menggunakan $scope . Di AngularJS, setiap $scope mewarisi $scope , yang disebut $rootScope di level tertinggi. ( $scope agak berbeda dari arahan tradisional. Mereka memiliki ruang lingkup tindakan tertentu dan hanya mewarisi properti yang dinyatakan secara eksplisit.)
Karena karakteristik pewarisan prototipe, tidak penting untuk berbagi data antara kelas orang tua dan anak, tetapi jika Anda tidak hati -hati, mudah untuk menyalahgunakan properti dari $scope orang tua.
Misalnya, kita perlu menampilkan nama pengguna pada bilah navigasi, yang dimasukkan dalam formulir login. Upaya berikut harus berhasil:
<Div ng-controller = "navctrl"> <span> {{user}} </span> <div ng-controller = "loginctrl"> <span> {{user}} </span> <input ng-model = "user"> </input> </div> </div>Maka pertanyaannya adalah ...: Model NG pengguna diatur dalam input teks. Ketika pengguna memasukkan konten, template mana yang akan diperbarui? navctrl atau loginctrl, atau semuanya?
Jika Anda memilih loginctrl, maka Anda mungkin mengerti bagaimana prototipe warisan bekerja.
Rantai prototipe tidak berfungsi saat Anda mengambil literal. Jika NAVCTRL juga diperbarui secara bersamaan, perlu untuk mengambil rantai prototipe; Tetapi jika nilainya adalah objek, ini akan terjadi. (Ingat, dalam javascript, fungsi, array, dan objek semuanya adalah objek)
Jadi untuk mendapatkan perilaku yang diharapkan, Anda perlu membuat objek di NAVCTRL, yang dapat dirujuk oleh loginctrl.
<Div ng-controller = "navctrl"> <span> {{user.name}} </span> <v ng-controller = "loginctrl"> <span> {{user.name}} </span> <input ng-model = "user.name"> </input> </span> <input ng-model = "user.name"> </input> </span> <input ng-model = "user.name"> </input> Sekarang, karena pengguna adalah objek, rantai prototipe akan berfungsi, dan template NAVCTRL dan $scope dan loginCtrl akan diperbarui.
Ini sepertinya contoh yang cukup buatan, tetapi masalah ini dapat dengan mudah muncul ketika Anda menggunakan instruksi tertentu untuk membuat $scope anak, seperti ngRepeat .
9. Pengujian Manual
Karena TDD mungkin bukan cara yang lebih disukai oleh setiap pengembang, mereka melakukan pengujian manual ketika mereka memeriksa apakah kode tersebut berfungsi atau mempengaruhi sesuatu yang lain.
Tidak masuk akal untuk tidak menguji aplikasi AngularJS. AngularJS dirancang untuk membuatnya dapat diuji dari awal, dan injeksi ketergantungan dan modul Ngmock adalah bukti dari ini. Tim inti AngularJS telah mengembangkan banyak alat yang dapat mengambil pengujian ke tingkat berikutnya.
9.1 Bahan belakang
Pengujian unit adalah dasar pekerjaan pengujian, tetapi mempertimbangkan semakin kompleksitas aplikasi, pengujian integrasi lebih dekat dengan situasi aktual. Untungnya, tim inti AngularJS telah menyediakan alat yang diperlukan.
Kami telah membentuk busur derajat, penguji ujung ke ujung untuk mensimulasikan interaksi pengguna, yang dapat membantu Anda memverifikasi kesehatan program AngularJS Anda.
GotRactor menggunakan kerangka uji melati untuk menentukan tes. Gotraktor memiliki API yang sangat kuat untuk perilaku interaksi halaman yang berbeda.
Kami memiliki beberapa alat pengujian end-to-end lainnya, tetapi keuntungan dari busur derajat adalah bahwa ia memahami cara bekerja dengan kode AngularJS, terutama dalam siklus $ digest.
9.2 Karma
Setelah kami menyelesaikan penulisan tes integrasi dengan busur derajat, langkah selanjutnya adalah menjalankan tes. Menunggu tes dieksekusi, terutama tes integrasi, adalah kesedihan yang samar bagi setiap pengembang. Tim inti AngularJS juga merasa sangat tertekan, sehingga mereka mengembangkan karma.
Karma adalah penguji yang membantu mematikan loop umpan balik. Karma dapat melakukan ini karena menjalankan tes ketika file yang ditentukan diubah. Karma juga akan menjalankan tes pada beberapa browser, dan perangkat yang berbeda juga dapat menunjuk ke server Karma, yang dapat lebih baik mencakup skenario aplikasi dunia nyata.
10. Gunakan jQuery
JQuery adalah perpustakaan yang keren, dengan pengembangan lintas platform standar, dan hampir menjadi kebutuhan untuk pengembangan web modern. Namun, meskipun begitu banyak fitur jQuery yang sangat baik, filosofinya tidak konsisten dengan AngularJS.
AngularJS adalah kerangka kerja untuk membangun aplikasi, sedangkan jQuery adalah perpustakaan yang menyederhanakan "operasi dokumen HTML, pemrosesan acara, animasi dan jax". Ini adalah perbedaan paling mendasar antara keduanya. AngularJS berkomitmen pada arsitektur program dan tidak ada hubungannya dengan halaman HTML.
Untuk lebih memahami cara membangun program AngularJS, silakan berhenti menggunakan jQuery. JQuery memungkinkan pengembang untuk memikirkan masalah dengan standar HTML yang ada, tetapi seperti yang dikatakan dokumentasi, "AngularJS memungkinkan Anda untuk memperluas istilah HTML dalam aplikasi Anda."
Operasi DOM hanya boleh dilakukan dalam instruksi, tetapi itu tidak berarti mereka hanya dapat dienkapsulasi dengan jQuery. Sebelum Anda menggunakan jQuery, Anda harus selalu memikirkan apakah fungsi ini sudah disediakan oleh AngularJS. Sangat kuat untuk membuat alat yang kuat ketika instruksi bergantung satu sama lain.
Tetapi jQuery yang sangat hebat adalah suatu keharusan ketika hari itu mungkin terjadi, tetapi memperkenalkannya di tempat pertama adalah kesalahan umum.
Meringkaskan
AngularJS adalah kerangka kerja yang sangat baik yang selalu membaik dengan bantuan masyarakat. Meskipun AngularJS masih merupakan konsep yang berkembang, saya berharap orang dapat mengikuti konvensi yang disebutkan di atas untuk menghindari masalah yang dihadapi dalam mengembangkan aplikasi AngularJS. Saya berharap konten artikel ini akan membantu semua orang. Jika Anda memiliki pertanyaan, Anda dapat meninggalkan pesan untuk berkomunikasi. Terima kasih atas dukungan Anda ke wulin.com.