john's tech blog

hope is coming


  • 首页

  • 标签

  • 归档

angular-compileProvider

发表于 2017-07-27 | 更新于 2019-05-07

compileProvider是如何调用的

compileProvider定义

1
2
3
4
5
6
7
//为了在injectionArgs方法中 annotate中返回 然后给injectionArgs 使用
$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
function $CompileProvider($provide, $$sanitizeUriProvider) {
this.directive = function registerDirective(name, directiveFactory) {};

this.$get = [];
}

我们回到publishExternalAPI函数看compileProvider的调用:

publishExternalAPI

1
2
3
//instanceInjector 调用invoke函数
//invoke函数内部调用
$provide.provider('$compile', $CompileProvider)

$provide.provider

实例化provider

1
2
3
4
5
6
7
8
9
10
11
12
13
function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');
if (isFunction(provider_) || isArray(provider_)) {
//通过providerInjector实例化compileProvider
//所以是从providerCache中获取参数
provider_ = providerInjector.instantiate(provider_);
}
//没有定义$get函数会报错
if (!provider_.$get) {
throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
}
return providerCache[name + providerSuffix] = provider_;
}

instantiate

$provide.Provider的时候会调用此方法实例化provider,比如CompileProvider

1
2
3
4
5
6
7
8
9
10
function instantiate(Type, locals, serviceName) {
// Check if Type is annotated and use just the given function at n-1 as parameter
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
//注入参数 从providerCache中获取参数
var args = injectionArgs(Type, locals, serviceName);
// Empty object at position 0 is ignored for invocation with `new`, but required.
args.unshift(null);
return new (Function.prototype.bind.apply(ctor, args))();
}

instanceInjector.invoke

1
2
3
4
5
6
7
8
9
10
11
12
```js
var injector = createInjector(modules, config.strictDi);
//invoke的时候会从instanceCache中去找,找不到会从providerCache中去找,然后调用provider.$get方法
//所以也就解释了下面为什么能直接调用compile函数
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() { //rootScope
element.data('$injector', injector);
compile(element)(scope);
});
}]
);

angular_源码分析之rootElement

发表于 2017-07-26 | 更新于 2019-05-07

rootElementProvider

rootElementProvider是从哪来的,我们先来看段源码中的话:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
* @ngdoc service
* @name $rootElement
*
* @description
* The root element of Angular application. This is either the element where {@link
* ng.directive:ngApp ngApp} was declared or the element passed into
* {@link angular.bootstrap}. The element represents the root element of application. It is also the
*根元素
* location where the application's {@link auto.$injector $injector} service gets
* published, and can be retrieved using `$rootElement.injector()`.
*/

// the implementation is in angular.bootstrap
//实现在angular.bootstrap函数中

我们回到bootstrap函数中一探究竟:

bootstrap

1
2
3
4
5
6
7
8
function bootstrap(element, modules, config) {
modules = modules || [];
//unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。
modules.unshift(['$provide', function($provide) {
//调用$provide方法
$provide.value('$rootElement', element);
}]);
}

调用了$provide的value方法

$provide.value

1
2
3
//用个valueFn包装下,再调用factory方法
//不需要返回值,所以第三个参数传false
function value(name, val) { return factory(name, valueFn(val), false); }

$provide.factory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
}

//返回一个方法而已,方法里要调用factory方法
//相当于一定要有返回值
function enforceReturnValue(name, factory) {
return function enforcedReturnValue() {
var result = instanceInjector.invoke(factory, this);
if (isUndefined(result)) {
throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
}
return result;
};
}

$provide.provider

最终调用provider方法,provider后缀为

= 'Provider',```
1
2
3
4
5
6
7
8
9
10
11
12
13
```js

function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);
}
//没有定义$get函数会报错
if (!provider_.$get) {
throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
}
return providerCache[name + providerSuffix] = provider_;
}

angular_源码分析之启动过程

发表于 2017-07-26 | 更新于 2019-05-07

启动过程

在angular启动过程中会经历以下步骤:

publishExternalAPI

函数中会加载扩展函数,定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

### angularInit

angularInit函数中会调用```bootstrap```,bootstrap中会调用```createInjector```方法完成依赖注入,然后调用```invoke```启动编译服务

```js
////通过createInjector方法会调用注入时提供的ng模块中的configFn
//configFn中提供了$rootScope, $rootElement, $compile, $injector
//通过$provide.provider方法提供
//modules中首先就是ng模块
var injector = createInjector(modules, config.strictDi);
//$rootScope,$rootElement,$compile,$injector都是在publishExternalAPI中
//注入ng模块时由$provide.provider提供的
//$rootElement在bootstrap中
// modules.unshift(['$provide', function($provide) {
// $provide.value('$rootElement', element);
// }]);
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() { //rootScope
element.data('$injector', injector);
compile(element)(scope);
});
}]
);

createInjector

1
var runBlocks = loadModules(modulesToLoad);

loadModules是createInjector内部方法,方法中会调用

= angularModule(module);```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
获取模块。  

因为定义ng模块时是push到configBlocks中的,所以会直接调用runInvokeQueue

### runInvokeQueue
```js
//queue就是在定义ng 模块时因为有configFn参数,然后调用config 函数(实际是通过invokeLater返回的函数)push到configBlocks中。
var config = invokeLater('$injector', 'invoke', 'push', configBlocks);//configBlocks此时为空

function invokeLater(provider, method, insertMethod, queue) {
if (!queue) queue = invokeQueue;
return function() {
queue[insertMethod || 'push']([provider, method, arguments]);
return moduleInstance;
};
}

//此时queue就是['$injector','invoke',[['$provide',function($provide){}]]]
function runInvokeQueue(queue) {
var i, ii;
for (i = 0, ii = queue.length; i < ii; i++) {
var invokeArgs = queue[i],

//loadModules为内部方法所以能直接调用providerInjector
//get方法就是返回injector对象的getService方法
provider = providerInjector.get(invokeArgs[0]);
//实际就是调用$injector的invoke方法
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);

}
}

invoke函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//调用runInvokeQueue时,fn就是['$provide',function($provide){}]
function invoke(fn, self, locals, serviceName) {
if (typeof locals === 'string') {
serviceName = locals;
locals = null;
}

//注入参数
//如果fn是数组那么会判断数组最后一个元素是否为函数
var args = injectionArgs(fn, locals, serviceName);
if (isArray(fn)) { //比如['$scope',function($scope){}]
fn = fn[fn.length - 1];//取数组的最后一个
}

if (!isClass(fn)) {
// http://jsperf.com/angularjs-invoke-apply-vs-switch
// #5388
//比如 var injector = angular.injector(["myModule"]);
//injector.invoke(function(myService){alert(myService.my);});
return fn.apply(self, args);
} else {
args.unshift(null);
return new (Function.prototype.bind.apply(fn, args))();
}
}

providerCache

$provide提供了provider方法,比如

$CompileProvider)```
1
2
3
4
5
6
7
8
9
10
11
12
13
14

```js
//providerInjector调用invoke函数时,getService
//是从providerCache中获取的
var providerCache = {
$provide: {
provider: supportObject(provider),
factory: supportObject(factory),
service: supportObject(service),
value: supportObject(value),
constant: supportObject(constant),
decorator: decorator
}
};

provider

1
2
3
4
5
6
7
8
9
10
11
12
13
//name $compile
//provider_ CompileProvider
//返回CompileProvider实例 并且放入providerCache中。
function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);
}
if (!provider_.$get) {
throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
}
return providerCache[name + providerSuffix] = provider_;
}

provider方法里其实调用了

1
2
3
4
5
6
7
8
9
10
11
12
```js
//Type就可能是函数类型
function instantiate(Type, locals, serviceName) {
// Check if Type is annotated and use just the given function at n-1 as parameter
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
var args = injectionArgs(Type, locals, serviceName);
// Empty object at position 0 is ignored for invocation with `new`, but required.
args.unshift(null);
//这样构造。。返回函数本身的对象,然后就可以链式调用了。
return new (Function.prototype.bind.apply(ctor, args))();
}

angular源码分析之reverseParams函数

发表于 2017-07-26 | 更新于 2019-05-07

reverseParams方法

出处

在angular注册指令方法里,如果name是数组,那么会调用forEach方法来遍历注册

1
forEach(name, reverseParams(registerDirective));

定义

1
2
3
4
5
6
7
8
9
/**
*因为forEach是value,key的顺序,但是key,value是最常用的。
* when using forEach the params are value, key, but it is often useful to have key, value.
* @param {function(string, *)} iteratorFn
* @returns {function(*, string)}
*/

function reverseParams(iteratorFn) {
return function(value, key) {iteratorFn(key, value);};
}

typescript声明

发表于 2017-07-20 | 更新于 2019-05-07

今天在看typescript 导入模块的时候,看到这么一个导入法:

import * as express from 'express'

文中提到了如下的问题

最后一行export = express,并且上面分别定义了一个 function express() 和namespace express,这种写法是比较特殊的,我一时也没法解释清楚,反正多参照 DefinitelyTyped 上其他模块的写法即可。这个问题归根结底是 express 模块通过 import * as express from ‘express’ 引入的时候,express本身又是一个函数,这种写法在早期的 Node.js 版本的程序和 NPM 模块中是比较流行的。

这个应该只和声明有关

然后就看到这篇文章,里面提到了用 tsc 编译成 commonjs

1
2
3
"use strict";
var moment = require('./moment');
console.log(typeof moment)

然后我自己试了一下在target为es5的情况下确实是编译成了如下js:

1
2
3
4
5
6
7
8
var express = require("express");
var app = express();
app.get('/', function (req, res) {
res.end('hello, world');
});
app.listen(3000, function () {
console.log('server is listening');
});

文中还提到了如何编写声明文件,然后我看了下express的声明文件:

确实是像如下

1
2
3
4
5
6
7
8
9
10
11
12
13
declare function e(): core.Express;

declare namespace e {
var static: typeof serveStatic;

export function Router(options?: RouterOptions): core.Router;

//内部接口 外部获取不到
interface RouterOptions {

}
}
export = e;

发现express可以定义Router,和内部的RouterOptions
参考资料Express 4.x API 中文手册

1…181920…47

John

232 日志
43 标签
GitHub Twitter
欢迎关注我的公众号:沉迷Spring
© 2023 johnwonder
由 Hexo 强力驱动 v3.2.0
|
主题 – NexT.Pisces v7.1.1
|
0%