angular依赖注入
如果您以前曾经构建过大型JavaScript应用程序,那么您将面临管理组件依赖项的任务。 您可以将组件视为功能块。 它可以是函数,对象或实例。 该块选择公开一个或多个公共方法。 它还可以选择隐藏非公共功能。 在本文中,我们将研究两个主要的库,AngularJS和RequireJS。 我们将分析他们如何使用依赖注入在整个应用程序中共享组件。
关于依赖注入的简短故事
当您需要一种简单的方法将一个或多个组件引入应用程序时,依赖注入就成为必需。 例如,假设您有两个名为database
和logger
组件。 假定database
组件公开了getAll
,findById
,create
,update
和delete
。logger
组件的公共API中只有一种方法saveNewLog
。 让我们假设logger
组件依赖于database
组件来起作用。 使用依赖注入,我们可以在创建过程中将database
组件作为依赖项传递给logger
组件。
只是为了您可以更好地可视化依赖项,我将用代码编写它。 请注意,实际语法取决于您使用的依赖项注入库。 Angular和RequireJS具有不同的语法,因此下面的代码是一个通用示例,稍后我们将简单介绍这两个库的实际表示形式。
这是database
API:
function database() {var publicApis = {getAll: function() {},findById: function(id) {},create: function(newObject) {},update: function(id, objectProperties) {},delete: function(id) {}};return publicApis;}
并且,这是logger
API:
function logger(database) {var publicApis = {saveNewLog: function() {}};return publicApis;}
如您所见,我们正在将database
组件传递到logger
的构造函数中。 应用程序中处理logger
实例化的部分必须为其提供database
组件实例。
需要依赖注入
现在我们对什么是依赖注入有了更多的了解,让我们确定一下它给表带来了什么好处。 如果您倡导良好JavaScript设计,那么依赖注入的一些好处对您可能显而易见。 如果不是,请让我解释一些一般的好处。 我相信无论您使用AngularJS还是RequireJS,它们都适用。
测试变得轻而易举
测试变得更加容易,因为您可以提供模拟的依赖关系而不是实际的实现。
关注点分离
依赖注入使您可以分离应用程序的各个部分,以便每个部分处理不同的工作。 在上面的示例中,database
模块仅涉及处理数据库。logger
模块仅负责记录数据,无论是在数据库,文件还是控制台中。 这样的好处是更容易交换依赖关系。 如果以后我们决定需要使用基于文件的数据库而不是传统的关系数据库,则只需传递另一个模块即可。 该模块只需要公开与database
模块相同的API方法,并且logger
模块将继续正常工作。
组件的可重用性
由于分离关注点的这种性质,我们可以重用组件。 这使得重用也遵循相同模式的外部库变得很容易。
依赖管理库
我们已经看到了一些好处,现在让我们比较一下游戏中的两个主要库– Angular和RequireJS。 RequireJS专门用于依赖性管理。 AngularJS不仅提供了依赖管理,还提供了更多功能,但我们仅关注该功能。
AngularJS
AngularJS具有这些称为配方的东西。 配方类似于先前描述的组件。 Angular组件的示例是工厂,指令和过滤器。 Angular提供了几种将组件注入其他内容的方法。 我们将以database
和logger
组件为例。
在深入探讨使用Angular进行依赖注入的不同方法之前,让我们首先构建示例场景。 假设我们有一个名为myModule
的Angular模块,让我们创建一个UserController
:
function UserController() {//some controller logic here}
我们还定义了database
和logger
服务:
myModule.factory('database', function() {var publicApis = {getAll: function() {},findById: function(id) {},create: function(newObject) {},update: function(id, objectProperties) {},delete: function(id) {}};return publicApis;});myModule.factory('logger', function(){var publicApis = {saveNewLog: function() {}};return publicApis;});
假设UserController
依靠logger
组件起作用。 当然,logger
组件仍取决于database
组件。 我们可以通过三种不同的方式表示AngularJS中的依赖关系。
参数名称推断
读取依赖项时,此方法取决于函数参数的名称。 我们可以将其应用到上面的示例中,如下所示:
function UserController(logger) {//some controller logic here to use injected logger factory}myModule.factory('database', function() {var publicApis = {getAll: function() {},findById: function(id) {},create: function(newObject) {},update: function(id, objectProperties) {},delete: function(id) {}};return publicApis;});myModule.factory('logger', function(database) {//use injected database factory herevar publicApis = {saveNewLog: function() {}};return publicApis;});
使用$inject
此依赖项注入方法在组件的功能上使用$inject
属性。$inject
属性应该是一个字符串数组,用于指定依赖项。 对于UserController
,这很容易做到。 对于logger
工厂,我们需要对上面的示例进行一些更改,以便可以将该属性添加到其功能中。 由于它是一个匿名函数,因此我们首先应将其定义为命名函数。 接下来,我们可以附加必需的属性,如下所示。
function UserController(logger) {//some controller logic here to use injected logger factory}UserController['$inject'] = ['logger'];myModule.factory('database', function() {var publicApis = {getAll: function() {},findById: function(id) {},create: function(newObject) {},update: function(id, objectProperties) {},delete: function(id) {}};return publicApis;});function loggerFactory(database) {//use injected database factory herevar publicApis = {saveNewLog: function() {}};return publicApis;}loggerFactory['$inject'] = ['database'];myModule.factory('logger', loggerFactory);
使用数组符号
第三种方式涉及在定义UserController
和logger
工厂时将数组作为第二个参数传递。 在这里,我们还必须更改定义UserController
的方式,以便可以使用此方法。
function UserController(loggerFactory) {//some controller logic here to use injected logger factory}myModule.controller('UserController', ['logger', UserController]);myModule.factory('database', function() {var publicApis = {getAll: function() {},findById: function(id) {},create: function(newObject) {},update: function(id, objectProperties) {},delete: function(id) {} };return publicApis;});function loggerFactory(database) {//use injected database factory herevar publicApis = {saveNewLog: function() {}};return publicApis;}myModule.factory('logger', ['database', loggerFactory]);
需求JS
RequireJS的依赖注入通过在文件中包含组件来工作。 每个组件都位于其自己的单独文件中。 AngularJS预先加载组件,而RequireJS仅在需要时加载组件。 它通过对服务器进行Ajax调用来获取该文件所在组件的文件。
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95您的完全免费
让我们看看RequireJS如何在语法上处理依赖项注入。 我将跳过如何设置RequireJS。 为此,请参阅此SitePoint 文章 。
与RequireJS依赖注入有关的两个主要功能是define
和require
。 简而言之,define
函数创建一个组件,而require
函数用于在执行代码块之前加载一组依赖项。 让我们更深入地检查这两个功能。
define
功能
继续使用logger
和database
示例,让我们将它们创建为组件(filename:
注释指示我们实际定义组件的位置):
//filename: database.jsdefine([], function() {var publicApis = {getAll: function() {},findById: function(id) {},create: function(newObject) {},update: function(id, objectProperties) {},delete: function(id) {}};return publicApis;});//filename: logger.jsdefine(['database'], function(database) {//use database component here somewherevar publicApis = {saveNewLog: function(logInformation) {}};return publicApis;});
如您所见,define
函数带有两个参数。 第一个是可选的组件数组,必须先加载这些组件,然后才能定义组件。 第二个参数是必须返回某些内容的函数。 您可能会注意到,我们传入database
组件作为定义logger
模块的依赖项。database
组件不依赖任何其他组件。 因此,它的define
函数将一个空数组作为第一个参数。
require
功能
现在,让我们看一下使用已定义组件的场景。 让我们模拟记录一些信息。 由于我们需要logger
组件能够使用其代码,因此必须使用require
函数将其拉入。
require(['logger'], function(logger) {//some code herelogger.saveNewLog('log information');});
从上面可以看到,require
函数仅用于运行一些代码,不返回任何内容。 它接受的第一个参数是一组依赖模块。 第二个是当那些依赖项已加载时运行的函数。 该函数接受的参数与要加载的依赖项一样多。 每个代表相应的组件。
结论
在依赖注入方面,这使我们结束了AngularJS和RequireJS之间的比较。 尽管两者采用的方法截然不同,但没有理由不能将它们一起使用。 请让我们知道您使用这两个库的经验,或者您还有其他需要添加的内容。
翻译自: /dependency-injection-angular-vs-requirejs/
angular依赖注入