Thay vào đó chỉ cần điền vào bảng với "có" và "không" mà không có lời giải thích, tôi sẽ đi vào chi tiết hơn một chút.
[Lưu ý, được thêm vào sau khi hoàn thành: điều này cuối cùng đã ... khá lâu hơn tôi mong đợi. Có một tl; dr ở phía dưới, nhưng tôi hy vọng điều này chứng minh thông tin.]
[Câu trả lời này cũng đã được thêm vào wiki AngularJS: Hiểu về tiêm phụ thuộc ]
Các $provide
dịch vụ có trách nhiệm nói với góc làm thế nào để tạo ra những điều tiêm mới; những thứ này được gọi là dịch vụ . Dịch vụ được xác định bởi những thứ được gọi là nhà cung cấp , đó là những gì bạn đang tạo khi bạn sử dụng $provide
. Việc xác định nhà cung cấp được thực hiện thông qua provider
phương thức trên $provide
dịch vụ và bạn có thể nắm giữ $provide
dịch vụ bằng cách yêu cầu dịch vụ đó được đưa vào config
chức năng của ứng dụng . Một ví dụ có thể là một cái gì đó như thế này:
app.config(function($provide) {
$provide.provider('greeting', function() {
this.$get = function() {
return function(name) {
alert("Hello, " + name);
};
};
});
});
Ở đây chúng tôi đã xác định một nhà cung cấp mới cho một dịch vụ được gọi là greeting
; chúng ta có thể đưa một biến có tên greeting
vào bất kỳ chức năng có thể tiêm nào (như bộ điều khiển, nhiều hơn về sau) và Angular sẽ gọi $get
hàm của nhà cung cấp để trả về một phiên bản mới của dịch vụ. Trong trường hợp này, thứ sẽ được thêm vào là một hàm lấy name
tham số và alert
sa thông báo dựa trên tên. Chúng tôi có thể sử dụng nó như thế này:
app.controller('MainController', function($scope, greeting) {
$scope.onClick = function() {
greeting('Ford Prefect');
};
});
Bây giờ đây là mẹo. factory
, service
và value
tất cả chỉ là các phím tắt để xác định các phần khác nhau của nhà cung cấp - nghĩa là, họ cung cấp một phương tiện để xác định nhà cung cấp mà không phải nhập tất cả nội dung đó. Ví dụ: bạn có thể viết chính xác cùng một nhà cung cấp như thế này:
app.config(function($provide) {
$provide.factory('greeting', function() {
return function(name) {
alert("Hello, " + name);
};
});
});
Điều quan trọng là phải hiểu, vì vậy tôi sẽ viết lại: dưới mui xe, AngularJS đang gọi chính xác mã mà chúng tôi đã viết ở trên ( $provide.provider
phiên bản) cho chúng tôi. Có nghĩa đen, 100% không có sự khác biệt trong hai phiên bản. value
hoạt động theo cùng một cách - nếu bất cứ điều gì chúng ta sẽ trả về từ $get
hàm của chúng ta (còn gọi là factory
hàm của chúng ta ) luôn giống hệt nhau, chúng ta có thể viết mã thậm chí ít hơn bằng cách sử dụng value
. Ví dụ: vì chúng tôi luôn trả lại cùng chức năng cho greeting
dịch vụ của mình, chúng tôi cũng có thể sử dụng value
để xác định chức năng đó:
app.config(function($provide) {
$provide.value('greeting', function(name) {
alert("Hello, " + name);
});
});
Một lần nữa, điều này giống hệt 100% với hai phương thức khác mà chúng ta đã sử dụng để xác định hàm này - đó chỉ là một cách để lưu một số cách gõ.
Bây giờ bạn có thể nhận thấy điều phiền toái app.config(function($provide) { ... })
này tôi đã sử dụng. Do việc xác định các nhà cung cấp mới (thông qua bất kỳ phương thức đã cho nào ở trên) rất phổ biến, AngularJS trưng ra các $provider
phương thức trực tiếp trên đối tượng mô-đun, để tiết kiệm hơn nữa việc gõ:
var myMod = angular.module('myModule', []);
myMod.provider("greeting", ...);
myMod.factory("greeting", ...);
myMod.value("greeting", ...);
Tất cả đều làm điều tương tự như các app.config(...)
phiên bản dài hơn mà chúng ta đã sử dụng trước đây.
Thuốc tiêm mà tôi đã bỏ qua cho đến nay là constant
. Bây giờ, thật dễ dàng để nói rằng nó hoạt động như thế nào value
. Chúng ta sẽ thấy có một sự khác biệt sau.
Để xem xét , tất cả các đoạn mã này đang thực hiện cùng một điều chính xác :
myMod.provider('greeting', function() {
this.$get = function() {
return function(name) {
alert("Hello, " + name);
};
};
});
myMod.factory('greeting', function() {
return function(name) {
alert("Hello, " + name);
};
});
myMod.value('greeting', function(name) {
alert("Hello, " + name);
});
Người tiêm có trách nhiệm thực sự tạo ra các phiên bản dịch vụ của chúng tôi bằng cách sử dụng mã chúng tôi cung cấp thông qua $provide
(không có ý định chơi chữ). Bất cứ khi nào bạn viết một hàm lấy các đối số được chèn, bạn sẽ thấy trình tiêm tại nơi làm việc. Mỗi ứng dụng AngularJS có một ứng dụng $injector
được tạo khi ứng dụng bắt đầu; bạn có thể nắm giữ nó bằng cách tiêm $injector
vào bất kỳ chức năng tiêm nào (vâng, $injector
biết cách tự tiêm!)
Khi bạn đã có $injector
, bạn có thể lấy một phiên bản của một dịch vụ được xác định bằng cách gọi get
nó với tên của dịch vụ. Ví dụ,
var greeting = $injector.get('greeting');
greeting('Ford Prefect');
Người tiêm cũng có trách nhiệm tiêm dịch vụ vào các chức năng; ví dụ, bạn có thể tiêm dịch vụ một cách kỳ diệu vào bất kỳ chức năng nào bạn có bằng invoke
phương pháp của người tiêm ;
var myFunction = function(greeting) {
greeting('Ford Prefect');
};
$injector.invoke(myFunction);
Cần lưu ý rằng người tiêm sẽ chỉ tạo một thể hiện của dịch vụ một lần . Sau đó, nó lưu trữ bất cứ thứ gì nhà cung cấp trả về bằng tên của dịch vụ; lần sau khi bạn yêu cầu dịch vụ, bạn sẽ thực sự có được cùng một đối tượng.
Vì vậy, để trả lời câu hỏi của bạn, bạn có thể đưa dịch vụ vào bất kỳ chức năng nào được gọi với$injector.invoke
. Điêu nay bao gôm
- chức năng định nghĩa bộ điều khiển
- chức năng định nghĩa chỉ thị
- chức năng định nghĩa bộ lọc
- các
$get
phương thức của nhà cung cấp (còn gọi là các factory
hàm định nghĩa)
Vì constant
s và value
s luôn trả về một giá trị tĩnh, chúng không được gọi thông qua bộ tiêm, và do đó bạn không thể tiêm chúng với bất cứ thứ gì.
Cấu hình nhà cung cấp
Bạn có thể tự hỏi tại sao người ta bận tâm để thiết lập một nhà cung cấp chính thức với các provide
phương pháp nếu factory
, value
vv rất dễ dàng hơn nhiều. Câu trả lời là các nhà cung cấp cho phép rất nhiều cấu hình. Chúng tôi đã đề cập rằng khi bạn tạo một dịch vụ thông qua nhà cung cấp (hoặc bất kỳ phím tắt nào mà Angular cung cấp cho bạn), bạn sẽ tạo một nhà cung cấp mới xác định cách thức dịch vụ đó được xây dựng. Điều tôi không đề cập là các nhà cung cấp này có thể được đưa vào config
các phần trong ứng dụng của bạn để bạn có thể tương tác với họ!
Đầu tiên, Angular chạy ứng dụng của bạn theo hai giai đoạn - giai đoạn config
và run
giai đoạn. Các config
giai đoạn, như chúng ta đã thấy, là nơi bạn có thể thiết lập bất kỳ nhà cung cấp khi cần thiết. Đây cũng là nơi chỉ thị, bộ điều khiển, bộ lọc và những thứ tương tự được thiết lập. Các run
giai đoạn, như bạn có thể đoán, là nơi góc thực sự biên dịch DOM của bạn và khởi động ứng dụng của bạn.
Bạn có thể thêm mã bổ sung để được chạy trong các giai đoạn này với các hàm myMod.config
và myMod.run
hàm - mỗi hàm có một chức năng để chạy trong giai đoạn cụ thể đó. Như chúng ta đã thấy trong phần đầu tiên, các hàm này có thể được tiêm - chúng ta đã thêm $provide
dịch vụ tích hợp trong mẫu mã đầu tiên của mình. Tuy nhiên, điều đáng chú ý là trong config
giai đoạn này, chỉ các nhà cung cấp mới có thể được tiêm (ngoại trừ các dịch vụ trong mô- AUTO
đun-- $provide
và $injector
).
Ví dụ: những điều sau đây không được phép :
myMod.config(function(greeting) {
// WON'T WORK -- greeting is an *instance* of a service.
// Only providers for services can be injected in config blocks.
});
Những gì bạn làm có quyền truy cập vào bất kỳ nhà cung cấp cho dịch vụ mà bạn đã thực hiện:
myMod.config(function(greetingProvider) {
// a-ok!
});
Có một ngoại lệ quan trọng: constant
s, vì chúng không thể thay đổi, được phép tiêm vào bên trong config
các khối (đây là cách chúng khác với value
s). Họ được truy cập bằng tên của họ một mình (không có Provider
hậu tố cần thiết).
Bất cứ khi nào bạn xác định nhà cung cấp dịch vụ, nhà cung cấp đó sẽ được đặt tên serviceProvider
, service
tên của dịch vụ đó ở đâu. Bây giờ chúng ta có thể sử dụng sức mạnh của các nhà cung cấp làm một số thứ phức tạp hơn!
myMod.provider('greeting', function() {
var text = 'Hello, ';
this.setText = function(value) {
text = value;
};
this.$get = function() {
return function(name) {
alert(text + name);
};
};
});
myMod.config(function(greetingProvider) {
greetingProvider.setText("Howdy there, ");
});
myMod.run(function(greeting) {
greeting('Ford Prefect');
});
Bây giờ chúng tôi có một chức năng trên nhà cung cấp của chúng tôi được gọi là setText
chúng tôi có thể sử dụng để tùy chỉnh alert
; chúng tôi có thể truy cập vào nhà cung cấp này trong một config
khối để gọi phương thức này và tùy chỉnh dịch vụ. Cuối cùng khi chúng tôi chạy ứng dụng của mình, chúng tôi có thể lấy greeting
dịch vụ và dùng thử để thấy rằng tùy chỉnh của chúng tôi có hiệu lực.
Vì đây là một ví dụ phức tạp hơn, đây là một minh chứng hoạt động: http://jsfiddle.net/BinaryMuse/9GjYg/
Các chức năng của bộ điều khiển có thể được đưa vào, nhưng bản thân các bộ điều khiển không thể được tiêm vào những thứ khác. Đó là bởi vì bộ điều khiển không được tạo thông qua nhà cung cấp. Thay vào đó, có một dịch vụ Angular tích hợp được gọi $controller
là chịu trách nhiệm thiết lập bộ điều khiển của bạn. Khi bạn gọi myMod.controller(...)
, bạn thực sự đang truy cập nhà cung cấp dịch vụ này , giống như trong phần trước.
Ví dụ: khi bạn xác định bộ điều khiển như thế này:
myMod.controller('MainController', function($scope) {
// ...
});
Những gì bạn đang thực sự làm là đây:
myMod.config(function($controllerProvider) {
$controllerProvider.register('MainController', function($scope) {
// ...
});
});
Sau này, khi Angular cần tạo một thể hiện của bộ điều khiển của bạn, nó sẽ sử dụng $controller
dịch vụ (lần lượt sử dụng $injector
chức năng để gọi hàm điều khiển của bạn để nó cũng được thêm vào các phụ thuộc của nó).
Bộ lọc và Chỉ thị
filter
và directive
làm việc chính xác theo cách tương tự như controller
; filter
sử dụng một dịch vụ được gọi $filter
và nhà cung cấp của nó $filterProvider
, trong khi directive
sử dụng một dịch vụ được gọi $compile
và nhà cung cấp của nó $compileProvider
. Một số liên kết:
Theo các ví dụ khác, myMod.filter
và myMod.directive
là các phím tắt để cấu hình các dịch vụ này.
Vì vậy, để tóm tắt, bất kỳ chức năng nào được gọi với $injector.invoke
có thể được đưa vào . Điều này bao gồm, từ biểu đồ của bạn (nhưng không giới hạn):
- bộ điều khiển
- chỉ thị
- nhà máy
- bộ lọc
- nhà cung cấp
$get
(khi xác định nhà cung cấp là một đối tượng)
- Hàm nhà cung cấp (khi xác định nhà cung cấp là hàm xây dựng)
- dịch vụ
Nhà cung cấp tạo ra các dịch vụ mới có thể được tiêm vào mọi thứ . Điêu nay bao gôm:
- không thay đổi
- nhà máy
- các nhà cung cấp
- dịch vụ
- giá trị
Điều đó nói rằng, các dịch vụ tích hợp như $controller
và $filter
có thể được tiêm, và bạn có thể sử dụng các dịch vụ đó để nắm giữ các bộ lọc và bộ điều khiển mới mà bạn đã xác định bằng các phương thức đó (mặc dù chính những điều bạn xác định không thể tiêm vào vật).
Ngoài ra, bất kỳ chức năng nào được gọi là có thể được tiêm với bất kỳ dịch vụ nào do nhà cung cấp cung cấp - không có hạn chế nào (ngoài những khác biệt config
và run
được liệt kê ở đây).