依赖注入:Angular vs. RequireJS

如果您以前曾经构建过大型JavaScript应用程序,那么您将面临管理组件依赖项的任务。 您可以将组件视为功能块。 它可以是函数,对象或实例。 该块选择公开一个或多个公共方法。 它还可以选择隐藏非公共功能。 在本文中,我们将研究两个主要的库,AngularJS和RequireJS。 我们将分析他们如何使用依赖注入在整个应用程序中共享组件。

关于依赖注入的简短故事

当您需要一种简单的方法将一个或多个组件引入应用程序时,依赖注入就成为必需。 例如,假设您有两个名为databaselogger组件。 假设database组件公开了getAllfindByIdcreateupdatedeletelogger组件的公共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提供了几种将组件注入其他内容的方法。 我们将以databaselogger组件为例。

在深入探讨使用Angular进行依赖注入的不同方法之前,让我们首先构建示例场景。 假设我们有一个名为myModule的Angular模块,让我们创建一个UserController

function UserController() {//some controller logic here
}

我们还定义了databaselogger服务:

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);

使用数组符号

第三种方法涉及在定义UserControllerlogger工厂时将数组作为第二个参数传递。 在这里,我们还必须更改定义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调用来获取该文件所在组件的文件。

让我们看看RequireJS如何在语法上处理依赖注入。 我将跳过如何设置RequireJS。 为此,请参阅此SitePoint 文章 。

与RequireJS依赖注入有关的两个主要功能是definerequire 。 简而言之, define函数创建一个组件,而require函数用于在执行代码块之前加载一组依赖项。 让我们更深入地检查这两个功能。

define功能

继续使用loggerdatabase示例,让我们将它们创建为组件( filename:注释指示我们实际定义组件的位置):

//filename: database.js
define([], function() {var publicApis = {getAll: function() {},findById: function(id) {},create: function(newObject) {},update: function(id, objectProperties) {},delete: function(id) {}};return publicApis;
});//filename: logger.js
define(['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之间的比较。 尽管两者采用的方法截然不同,但没有理由不能将它们一起使用。 请让我们知道您使用这两个库的经验,或者是否还有其他要添加的内容。

From: https://www.sitepoint.com/dependency-injection-angular-vs-requirejs/


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部