gpt4 book ai didi

angularjs - 如何将 require.js 添加到我的 AngularJS 应用程序中?

转载 作者:行者123 更新时间:2023-12-04 00:11:18 27 4
gpt4 key购买 nike

我的 AngularJS 应用程序中有 Controller ,它们当前的编码如下:

app.controller('appController',
[
'$state',
'$timeout',
'enumService',
'userService',
'utilityService',
appController
]);

function appController(
$scope,
$state,
$timeout,
enumService,
userService,
utilityService
) {

...

}

我想开始做的是使用 require.js 来处理 Controller 的延迟加载。 我了解到我应该使用这样的东西:
require(["app"], function (app) {
app.controller('appController', function appController(
$scope,
$state,
$timeout,
enumService,
userService,
utilityService
) {

...

});
});

有人可以向我解释 app.controller 如何获得对服务的引用吗?我需要在 require.js 方面做任何其他事情吗?我对 appController 进行编码的方式是否正确?

最佳答案

tl;博士;最终解决方案在最后一节,或者直接查看 this plunk

延迟加载 $injector
angular-requirejs-seed项目说明了如何通过设置这样的延迟函数来轻松实现延迟加载:

define([], function() {
return ['$scope', '$http', 'myInjectable', function($scope, $http, myInjectable) {
$scope.welcomeMessage = 'hey this is myctrl2.js!';

// because this has happened async, we've missed the digest cycle
$scope.$apply();
}];
});

...然后像这样实例化 Controller :
.controller('MyCtrl2', ['$scope', '$injector', function($scope, $injector) {
require(['controllers/myctrl2'], function(myctrl2) {
$injector.invoke(myctrl2, this, {'$scope': $scope});
});
...

请注意,延迟加载的函数不是 Controller 。它只是一个用 $injector 调用的函数这使它可以访问实际控制人的 $scopethis , 并允许它访问您的应用程序中加载的任何注入(inject)项。

您可以将相同的技术应用于 服务 , 工厂 , 或 指令 .

延迟加载注意事项

大多数情况下,延迟加载可能会弄巧成拙 .如果您的目标是为您的用户提供一个活泼的网站,那么延迟加载每个 Controller 是一个坏主意。一旦建立了 HTTP 连接,大多数 Internet 连接允许大量数据在短时间内通过网络传输。然而,延迟可能是真正的杀手。这就是为什么现在大多数网站使用串联和缩小来打包他们的 javascript 并减少网络请求的数量,而不是依赖于增加请求数量的延迟加载。

考虑您的应用程序的架构。您将创建多少个可重用的指令?应用程序的各个部分将共享多少不适合延迟加载的代码?对于许多应用程序, 大部分代码将由通用组件组成,这使得延迟加载毫无意义 .

延迟加载在具有非常独特和独立部分的应用程序中有意义 .如此独特和独立的部分可以被认为是独立的应用程序。但是,即使在这种情况下,您也可能会考虑实际创建单独的应用程序,而不是将它们组合起来。


BTW, require.js is still useful even if you're not Lazy-loading

Even if you're not lazy-loading, require.js is extremely useful for dependency management. Used in conjunction with the require.js optimizer it's an elegant way to keep track of dependencies and compress+minify your app.

You can also use require.js to load dependencies for running Jasmine unit tests which helps keep your components modular, and speeds up your tests by just loading the dependencies that you need. For unit testing, I create a separate main-test.js file which calls require.config(...) to load app dependencies as well as testing-specific dependencies.




延迟加载架构

使用 angular 进行延迟加载相当复杂,因为 angular 并非旨在支持延迟加载。在本节中,我将尝试带您探索如何强制使用 angular 来支持延迟加载。这不是一个成熟的解决方案,但我希望介绍在构建此类应用程序时理解的重要概念。

让我们从路由器开始,与我在第一部分中介绍的 angular-requirejs-seed 不同,延迟加载实际上更适合应用程序的路由器。使用 用户界面路由器 ,我们可以通过这种方式实现延迟加载:
...
app.$controllerProvider = $controllerProvider;
var lazyPartialDeferred;

$stateProvider
...
.state('lazy', {
url: "/lazy",
templateProvider: function() { return lazyPartialDeferred.promise; },
controller: 'lazyCtrl',
resolve: {
load: function($q, $templateCache) {
var lazyCtrlDeferred = $q.defer();
lazyPartialDeferred = $q.defer();
require(['lazy'], function (lazy) {
lazyCtrlDeferred.resolve();
lazyPartialDeferred.resolve($templateCache.get('lazy.html'));
});
return lazyCtrlDeferred.promise;
}
}
});
...

我们在这里所做的是推迟部分(lazy.html)和 Controller (lazyCtrl)的实例化,直到加载我们的 requirejs 模块(lazy.js)之后。另外,请注意 我们直接从 $templateCache 加载我们的 View 部分,lazy.html .也就是说,当我们加载lazy.js 时,部分本身包含在lazy.js 中。理论上,我们可以单独加载lazy.html 和lazy.js,但为了获得最佳性能,我们应该将partials 编译到我们的js 文件中。

一起来看看 懒惰.js :
define(['angular', 'lazy-partials'], function (angular) {
var app = angular.module('app');

var lazyCtrl = ['$scope', '$compile', '$templateCache', function ($scope, $compile, $templateCache) {
$scope.data = 'my data';
}];

app.$controllerProvider.register('lazyCtrl', lazyCtrl);
});

请记住,上面的代码代表未编译的lazy.js。在生产中,lazy-partials.js(在上面第一行中引用)实际上会被编译到同一个文件中。

现在我们来看看 懒惰partials.js :
// Imagine that this file was actually compiled with something like grunt-html2js
// So, what you actually started with was a bunch of .html files which were compiled into this one .js file...
define(['angular'], function (angular) {
var $injector = angular.element(document).injector(),
$templateCache = $injector.get('$templateCache');

$templateCache.put('lazy.html', '<p>This is lazy content! and <strong>{{data}}</strong> <a href="#">go back</a></p>');
});

再一次,上面的代码并不是这样一个文件真正的样子。 lazy-partials.js 实际上会使用像 grunt-html2js 这样的构建工具插件从你的 html 文件中自动生成。

现在,理论上您可以使用目前介绍的方法构建整个应用程序。然而,它有点……笨拙。我们更愿意在lazy.js 中实例化一个新模块,例如 appLazy = angular.module('app.lazy')然后实例化我们的 Controller 、指令、服务等,如 appLazy.directive(...) .

然而,我们不能这样做的原因是所有这些东西都在 angular.bootstrap 中初始化(并提供给我们的应用程序)。在加载 lazy.js 时已经调用的方法。我们不能只是打电话 angular.bootstrap(...)再次。


BTW, internally angular is doing this to bootstrap modules:

      var injector = createInjector(modules, config.strictDi);

createInjector is an internal function to angular that loops through all of the modules and registers all of their various building blocks.

In lazy.js, we called $controllerProvider.register(..) to lazily register our controller. createInjector also triggers a call to the same function when the app is bootstrapped. Here is a list of various angular building blocks and the way in which they are registered by angular:

provider: $provide.provider
factory: $provide.factory
service: $provide.service
value: $provide.value
constant: $provide.constant.unshift
animation: $animateProvider.register
filter: $filterProvider.register
controller: $controllerProvider.register
directive: $compileProvider.directive



那么,有没有办法懒惰地实例化模块?是的, you can register a module and it's sub-modules by iterating through various nested properties of the module object ( requires and _invokeQueue ) ,该操作已在名为 的库中进行了简化。 ocLazyLoad .

本节中介绍的大部分代码都可以在 this plunker 中找到。 .

(以上未提及的灵感来源: Couch Potato , AngularAMD )

完整的延迟加载解决方案:

[ ocLazyLoad + ui-router + requirejs ] - plunk

因为 用户界面路由器允许我们延迟加载模板和 Controller ,我们可以将它与 结合使用ocLazyLoad 在路由更改之间即时加载模块。这个例子建立在上一节的原则之上,但是利用了 ocLazyLoad 我们有一个解决方案,允许我们的延迟加载模块以与非延迟加载模块相同的方式构建。

这里的关键是我们的 app.config(..)块:
  app.config(function($stateProvider, $locationProvider, $ocLazyLoadProvider) {
var lazyDeferred;

$ocLazyLoadProvider.config({
loadedModules: ['app'],
asyncLoader: require
});

$stateProvider
...
.state('lazy', {
url: "/lazy",
templateProvider: function() { return lazyDeferred.promise; },
controller: 'lazyCtrl',
resolve: {
load: function($templateCache, $ocLazyLoad, $q) {
lazyDeferred = $q.defer();
return $ocLazyLoad.load({
name: 'app.lazy',
files: ['lazy']
}).then(function() {
lazyDeferred.resolve($templateCache.get('lazy.html'));
});
}
}
});
...

懒惰.js 现在看起来像这样:
define(['angular', 'lazy-partials'], function (angular) {
var appLazy = angular.module('app.lazy', ['app.lazy.partials']);

appLazy.controller('lazyCtrl', function ($scope, $compile, $templateCache) {
$scope.data = 'my data';
});
});

请注意,就延迟加载而言,此文件不再有任何特殊之处。您可以以非惰性方式轻松加载此文件,而它不会知道其中的区别。同样的原则适用于 懒惰partials.js :
// Imagine that this file was actually compiled with something like grunt-html2js
// So, what you actually started with was a bunch of .html files which were compiled into this one .js file...
define(['angular'], function (angular) {
angular.module('app.lazy.partials', [])
.run(function($templateCache) {
$templateCache.put('lazy.html', '<p>This is lazy content! and <strong>{{data}}</strong> <a href="#">go back</a></p>');
});
});

>>> check out the fully-functioning plunk <<<

部署

在部署方面,这个难题的最后一部分是使用 requirejs 优化器来连接和最小化我们的 js 文件。理想情况下,我们希望优化器跳过主应用程序中已经包含的依赖项的串联(即:公共(public)文件)。为此, see this repo它伴随着 build.js file .

更优雅的解决方案

我们可以通过为 添加一个 ui-router 装饰器来改进之前的 plunk a very elegant solution .

关于angularjs - 如何将 require.js 添加到我的 AngularJS 应用程序中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23890623/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com