12/08/2018, 14:45

Các loại service trong AngularJS

Trong AngularJS có nhiều loại service. Và mỗi loại thì đều có cách dùng của nó. Tại sao chúng ta lại quyết định chọn A thay vì B. Với tính chất này thì nên dùng service nào. Kiểu như vậy. Cùng điểm qua một lượt các loại service trong Angular nhé. Provider, Factory, Service, Constant, Decorator, ...

Trong AngularJS có nhiều loại service. Và mỗi loại thì đều có cách dùng của nó. Tại sao chúng ta lại quyết định chọn A thay vì B. Với tính chất này thì nên dùng service nào. Kiểu như vậy.

Cùng điểm qua một lượt các loại service trong Angular nhé. Provider, Factory, Service, Constant, Decorator, Coffeescript.. Nhiều loại quá đúng không? Thế nên là cùng tìm hiểu đặc điểm của từng loại và chúng nên được dùng như thế nào nhé.

Provider

Đây là cha của hầu hết các loại service (trừ constant) và cũng là loại service phức tạp nhất nhưng đồng thời cũng dễ config nhất. Xem thử nhé:

app.provider('foo', function() {

  return {

    $get: function() {
      var thisIsPrivate = "Private";
      function getPrivate() {
        return thisIsPrivate;
      }

      return {
        variable: "This is public",
        getPrivate: getPrivate
      };
    }

  };

});

Một provider đơn giản như thế này, chỉ return function get. Như vậy là nếu ta có một controller và muốn inject provider foo vào, thì đơn giản là inject function get của nó là được.

Câu hỏi đặt ra là tại sao chúng ta sử dụng provider kiểu thế này trong khi factory cũng có thể. Lý do là chúng ta có thể config một provider trong hàm config. Như sau:

app.provider('foo', function() {

  var thisIsPrivate = "Private";

  return {

    setPrivate: function(newVal) {
      thisIsPrivate = newVal;
    },

    $get: function() {
      function getPrivate() {
        return thisIsPrivate;
      }

      return {
        variable: "This is public",
        getPrivate: getPrivate
      };
    }

  };

});

app.config(function(fooProvider) {
  fooProvider.setPrivate('New value from config');
});

Ở đây chúng ta chuyển thisIsPrivate ra ngoài hàm get và tạo thêm hàm setPrivate để có thể set giá trị cho thisIsPrivate trong hàm config. Tại sao phải làm vậy? Phải có cách dễ hơn để add hàm settter vào get chứ. Vậy là có mục đích khác ở đây rồi.

Hãy tưởng tượng chúng ta muốn tạo một thư viện để quản lý các models và một số REST petitions. Nếu mà chúng ta hardcore các URLs, không tạo hàm generic (chung) thì làm sao để config dễ. Vậy nên để dễ config các URLs này thì chúng ta tạo một provider và cho phép config các URLs ở trong đó.

Factory

Provider khá là linh hoạt và cũng khá là phức tạp. Thế nhưng khi mà không cần config thì thay vì dùng Provider, chúng ta có thể sử dụng Factory.

app.factory('foo', function() {
  var thisIsPrivate = "Private";
  function getPrivate() {
    return thisIsPrivate;
  }

  return {
    variable: "This is public",
    getPrivate: getPrivate
  };
});

// or..

app.factory('bar', function(a) {
  return a * 2;
});

Như code phía trên, chúng ta move hàm get của provider vào một factory với một syntax đơn giản hơn. Thực tế là trong nội bộ một factory chính là provider với hàm get. Chúng ta có thể inject mọi thứ trừ việc inject provider vào factory, constructor của provider và các hàm config.

Factory is good, but what if I just want to store a simple value? I mean, no injections, just a simple value or object. Well angular has you covered with the value service: Factory thì tốt nhưng nếu ta muốn lưu trữ một giá trị đơn giản thì sao? Có nghĩa là không có injections, chỉ đơn giản là 1 giá trị hoặc 1 object. Chẳng hạn như sau:

app.value('foo', 'A simple value');

Có thể thấy trong nội bộ value này là một factory. Và khi nó là một factory thì có nghĩa là nó không thể bị inject vào provider constructor hay các hàm config.

Service

Vậy thì Service là gì ở đây khi mà chúng ta đã có provider hay factory. Cùng xem thử ví dụ này:

app.service('foo', function() {
  var thisIsPrivate = "Private";
  this.variable = "This is public";
  this.getPrivate = function() {
    return thisIsPrivate;
  };
});

The service service works much the same as the factory one. The difference is simple: The factory receives a function that gets called when we create it and the service receives a constructor function where we do a new on it (actually internally is uses Object.create instead of new). Service ở đây hoạt động khá giống một factory. Và điểm khác biệt đơn giản là: factory thì nhận lại một function khi mà ta tạo ra nó, còn service thì nhận lại một constructor function khi ta thực hiện hàm new. Chẳng hạn như sau:

app.factory('foo2', function() {
  return new Foobar();
});


function Foobar() {
  var thisIsPrivate = "Private";
  this.variable = "This is public";
  this.getPrivate = function() {
    return thisIsPrivate;
  };
}

Foobar là một constructor function và chúng ta thể hiện nó ở factory khi angular xử lý nó lần đầu tiên và khi nó trả lại factory. Giống như service, Foobar có thể được khởi tạo instance chỉ một lần và lần tiếp theo sử dụng thì factory sẽ trả lại instance này.

Constant

Như trên đã nói thì constant là một loại khác với provider, nhưng cái dưới này thì không. Một constant hoạt động giống như value mà chúng ta có thể thấy dưới vd này:

app.constant('fooConfig', {
  config1: true,
  config2: "Default config2"
});

Vậy thì điều khác biệt là gì? Một constant có thể được inject mọi nơi và có thể inlcudes provider constructor cũng như các hàm config. Đó là lý do tại sao chúng ta sử dụng constant services để tạo các default config cho các directives, bởi vì chúng ta có thể modify các config này ở hàm config. You are wondering why it is called constant if we can modify it and well that was a design decision and I have no idea about the reasons behind it. Bạn có bao giờ tự hỏi tại sao nó được gọi là constant khi mà chúng ta có thể modify nó? Đơn giản chỉ là về mặt thiết kế mà thôi.

Conclusion

Các service là một trong các phần hay nhất của Angular. Và chúng ta có rất nhiều cách để tạo ra chúng, chỉ là đặt nó vào đúng hoàn cảnh và implement nó.

0