如何在不引发错误的情况下检查模块的存在?
Posted
技术标签:
【中文标题】如何在不引发错误的情况下检查模块的存在?【英文标题】:How to check for the existence of a module without an error being raised? 【发布时间】:2013-10-12 22:43:48 【问题描述】:在 Angular 1.2 中,ngRoute
是一个单独的模块,因此您可以使用其他社区路由器,例如 ui.router
。
我正在编写一个开源模块,旨在为多种不同的路由器实现工作。那么如何检查哪个路由器已加载或存在呢?
我在我的模块中的工厂内执行以下操作,但它没有按我期望的方式工作:
if (angular.module("ngRoute"))
// Do ngRoute-specific stuff.
else if (angular.module("ui.router"))
// Do ui.router-specific stuff.
它会为未加载的模块引发错误。例如,如果应用使用ui.router
,则ngRoute
检查会引发以下错误:
未捕获的错误:[$injector:nomod] 模块“ngRoute”不可用! 您要么拼错了模块名称,要么忘记加载它。如果 注册模块确保将依赖项指定为 第二个参数。
【问题讨论】:
我不知道是否有“正确”的做法,但我至少可以想到一个解决方法。你可以试试 angular.module('ngRoute') catch(e) //这里你知道它不存在 但可能有更好的方法。 【参考方案1】:我不知道有一种方法可以在不引发错误的情况下进行检查;但是,请注意问题在于它是Uncaught Error
,而不是引发了错误。捕获此类错误的模式如下。
try angular.module("ngRoute") catch(err) /* failed to require */
如果发现错误,你可以尝试另一个模块,如果没有,你可以使用第一个。
如果每个模块的行为都相同,您可以执行以下操作,其中我们定义了一个函数,它将尝试列出的模块名称中的第一个,如果抛出错误,请尝试下一个选项.
var tryModules = function(names)
// accepts a list of module names and
// attempts to load them, in order.
// if no options remain, throw an error.
if( names.length == 0 )
throw new Error("None of the modules could be loaded.");
// attempt to load the module into m
var m;
try
m = angular.module(names[0])
catch(err)
m = null;
// if it could not be loaded, try the rest of
// the options. if it was, return it.
if( m == null ) return tryModules(names.slice(1));
else return m;
;
tryModules(["ngRoute", "ui.router"]);
【讨论】:
这里m = angular.module("ngRoute");
需要改成m = angular.module(names[0]);
【参考方案2】:
我会测试服务而不是模块本身。
// In controller
if($injector.has('$route'))
if($injector.has('$state'))
// In angular config
if($injector.has('$routeProvider'))
if($injector.has('$stateProvider'))
【讨论】:
【参考方案3】:原来的答案是合法的。但是,作为替代方案,我在需要“查找或创建”模块时写了这个。有许多用例,但通常,它让您不必担心文件加载顺序。您可以将其放在initialModules.js
... 中,也可以在所有单个服务/指令文件的顶部以此类开头。这个小功能对我来说就像一个魅力:
var initialModules = [
name: 'app.directives', deps: ['ui.mask'],
name: 'app.services',
name: 'app.templates',
name: 'app.controllers'
];
initialModules.forEach(function(moduleDefinition)
findOrCreateModule(moduleDefinition.name, moduleDefinition.deps);
);
function findOrCreateModule(moduleName, deps)
deps = deps || [];
try
angular.module(moduleName);
catch (error)
angular.module(moduleName, deps);
///// OR... in like "myDirective.js"
findOrCreateModule('app.directives').directive('myDirective', myDirectiveFunction);
【讨论】:
试图找到一种方法向您发送消息,但我不太习惯所以我猜。这是一个非常好的解决问题的方法。我正要在我的所有文件之上编写一个 try-catch,但我想我会改用这个解决方案,在我的 app.js 中定义所有模块。编码好!【参考方案4】:如果您装饰 angular.module
以将名称存储在数组中,那么您可以检查该数组是否包含您的模块名称。
装饰 angular.module
见@dsfq's answer on SO。
这需要在加载 angular 之后但在开始加载任何 angular 模块之前发生。
检查您的模块
if(angular.modules.indexOf("ngRoute") > -1) ...
【讨论】:
【参考方案5】:不过,自动加载或创建模块的问题可以通过 gulp-angular-filesort 之类的东西更好地解决。 它真的完美无瑕。
来自gulp-angular-filesortgithub页面: 根据模块定义和使用情况自动对 AngularJS 应用文件进行排序
与 gulp-inject 结合使用,以正确的顺序注入您的 AngularJS 应用程序文件(脚本),以消除所有未捕获的错误:[$injector:modulerr]。
免责声明:我不隶属于 gulp-angular-filesort,我只使用它来获取大量利润。
【讨论】:
请从链接中添加一些内容。【参考方案6】:更好的解决方案是在创建模块时简单地进行检查。你只需要一个实用函数来添加回调。
//create a utility function to add a callback to object methods
//here we are making it a method of the underscore or lowdash object
//but it could be added to the angular global object or anything else
_.addCallBack = function (obj, originalMethodName, callBackMethod, context)
var fnOriginal = obj[originalMethodName],
outcome;
context = context || obj;
obj[originalMethodName] = function ()
var outcome = fnOriginal.apply(this, arguments);
callBackMethod.apply(this, arguments);
return outcome;
;
;
_.addCallBack(angular, "module", function(sModuleName, asDependencies)
if(_.contains(asDependencies, "ngRoute"))
//your logic here
//just loop through if you don't use underscore or lowdash
);
【讨论】:
【参考方案7】:AngularJS 1.6.3 及更高版本通过 $injector 服务拥有a way to check if a module is loaded。
在 1.6.7 中还添加了 ability to load new modules,这可能会引起某些人的兴趣。
【讨论】:
以上是关于如何在不引发错误的情况下检查模块的存在?的主要内容,如果未能解决你的问题,请参考以下文章
核心数据 - 如何在不触发错误的情况下检查对象关系是不是存在
如何在不引发事件的情况下设置 checkbox.isChecked