AngularJS: خدمة مقابل مزود مقابل المصنع




dependency-injection angularjs-service (20)

JS Fiddle Demo

مثال "Hello world" مع factory / service / provider :

var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!";
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!";
        }
    };
});
    
//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!";
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});
        

function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
    
    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
    {{hellos}}
</div>
</body>

ما هي الاختلافات بين Service والموفر Factory في AngularJS؟


مصنع

أنت تعطي AngularJS وظيفة ، سوف AngularJS تخزين مؤقت وضخ قيمة الإرجاع عند طلب المصنع.

مثال:

app.factory('factory', function() {
    var name = '';
    // Return value **is** the object that will be injected
    return {
        name: name;
    }
})

الاستعمال:

app.controller('ctrl', function($scope, factory) {
     $scope.name = factory.name;
});

الخدمات

أنت تعطي AngularJS وظيفة ، سوف AngularJS دعوة جديدة لتفعيل ذلك. إنها الحالة التي تنشئها AngularJS التي سيتم تخزينها مؤقتًا وحقنها عند طلب الخدمة. نظرًا لاستخدام ميزة جديدة في إنشاء الخدمة ، فإن الكلمة الرئيسية هذه صالحة وتشير إلى المثيل.

مثال:

app.service('service', function() {
     var name = '';
     this.setName = function(newName) {
         name = newName;
     }
     this.getName = function() {
         return name;
     }
});

الاستعمال:

app.controller('ctrl', function($scope, service) {
   $scope.name = service.getName();
});

مزود

يمكنك إعطاء AngularJS وظيفة ، وستقوم AngularJS باستدعاء $getوظيفتها. وهي قيمة الإرجاع من $getالدالة التي سيتم تخزينها مؤقتًا وحقنها عند طلب الخدمة.

يسمح لك الموفرون بتكوين الموفر قبل أن يقوم AngularJS بالاتصال $getبالطريقة للحصول على الحقن.

مثال:

app.provider('provider', function() {
     var name = '';
     this.setName = function(newName) {
          name = newName;
     }
     this.$get = function() {
         return {
            name: name
         }
     }
})

الاستخدام (كحقن في وحدة تحكم)

app.controller('ctrl', function($scope, provider) {
    $scope.name = provider.name;
});

الاستخدام ( $getيتم استدعاء تكوين الموفر قبل إنشاء الحقن)

app.config(function(providerProvider) {
    providerProvider.setName('John');
});

من قائمة بريد AngularJS حصلت على موضوع رائع يشرح خدمة مقابل مقابل مصنع واستخدام الحقن. تجميع الإجابات:

خدمات

بناء الجملة: module.service( 'serviceName', function );
النتيجة: عند التصريح عن serviceName كوسيطة قابلة للحقن ، سيتم تزويدك بمثيل للدالة. وبعبارة أخرى ، new FunctionYouPassedToService() .

المصانع

بناء الجملة: module.factory( 'factoryName', function );
النتيجة: عند التصريح بالتسمية factoryName كوسيطة للحقن ، سيتم تزويدك بالقيمة التي يتم إرجاعها من خلال استدعاء مرجع الوظيفة الذي تم تمريره إلى module.factory .

مقدمي

بناء الجملة: module.provider( 'providerName', function );
النتيجة: عند التصريح عن اسم الموفر كوسيطة قابلة للحقن ، سيتم تزويدك بـ (new ProviderFunction()).$get() . يتم إنشاء مثيل الدالة منشئ قبل أن يتم استدعاء الأسلوب $ get - ProviderFunction هو مرجع دالة تم تمريرها إلى module.provider.

يتمتع مزودي الخدمة بالميزة التي يمكن تهيئتها أثناء مرحلة تكوين الوحدة.

انظر here للرمز المقدم.

إليك شرحًا إضافيًا رائعًا من Misko:

provide.value('a', 123);

function Controller(a) {
  expect(a).toEqual(123);
}

في هذه الحالة ، يعيد الحاقن ببساطة القيمة كما هي. ولكن ماذا لو كنت ترغب في حساب القيمة؟ ثم استخدم المصنع

provide.factory('b', function(a) {
  return a*2;
});

function Controller(b) {
  expect(b).toEqual(246);
}

لذلك factory هو وظيفة مسؤولة عن خلق القيمة. لاحظ أن وظيفة المصنع يمكن أن تطلب تبعيات أخرى.

ولكن ماذا لو كنت تريد أن تكون أكثر OO ولديك فئة تسمى Greeter؟

function Greeter(a) {
  this.greet = function() {
    return 'Hello ' + a;
  }
}

ثم لتأكيد أنك سوف تضطر إلى الكتابة

provide.factory('greeter', function(a) {
  return new Greeter(a);
});

ثم يمكن أن نطلب "greeter" في وحدة تحكم مثل هذا

function Controller(greeter) {
  expect(greeter instanceof Greeter).toBe(true);
  expect(greeter.greet()).toEqual('Hello 123');
}

ولكن هذا هو كلام مفرط للغاية. طريقة أقصر لكتابة هذا سيكون provider.service('greeter', Greeter);

ولكن ماذا لو أردنا تكوين فئة Greeter قبل الحقن؟ ثم يمكننا أن نكتب

provide.provider('greeter2', function() {
  var salutation = 'Hello';
  this.setSalutation = function(s) {
    salutation = s;
  }

  function Greeter(a) {
    this.greet = function() {
      return salutation + ' ' + a;
    }
  }

  this.$get = function(a) {
    return new Greeter(a);
  };
});

ثم يمكننا القيام بذلك:

angular.module('abc', []).config(function(greeter2Provider) {
  greeter2Provider.setSalutation('Halo');
});

function Controller(greeter2) {
  expect(greeter2.greet()).toEqual('Halo 123');
}

كملاحظة جانبية ، يتم اشتقاق كل service factory value من مزود الخدمة.

provider.service = function(name, Class) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.instantiate(Class);
    };
  });
}

provider.factory = function(name, factory) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.invoke(factory);
    };
  });
}

provider.value = function(name, value) {
  provider.factory(name, function() {
    return value;
  });
};

TL، DR

1) عندما تستخدم مصنعًا ، يمكنك إنشاء كائن وإضافة خصائص إليه ثم إرجاع نفس الكائن. عند تمرير هذا المصنع إلى وحدة التحكم الخاصة بك ، ستتوفر الآن الخصائص الموجودة على الكائن في وحدة التحكم هذه من خلال المصنع.

app.controller(‘myFactoryCtrl’, function($scope, myFactory){
  $scope.artist = myFactory.getArtist();
});

app.factory(‘myFactory’, function(){
  var _artist = ‘Shakira’;
  var service = {};

  service.getArtist = function(){
    return _artist;
  }

  return service;
});


2) عندما تستخدم الخدمة ، تقوم AngularJS بتأسيسها خلف الكواليس باستخدام الكلمة الأساسية "الجديدة". وبسبب ذلك ، ستقوم بإضافة خصائص إلى "هذا" وستقوم الخدمة بإرجاع "هذا". عندما تقوم بتمرير الخدمة إلى وحدة التحكم الخاصة بك ، ستتوفر هذه الخصائص على 'this' هذه على وحدة التحكم هذه من خلال الخدمة الخاصة بك.

app.controller(‘myServiceCtrl’, function($scope, myService){
  $scope.artist = myService.getArtist();
});

app.service(‘myService’, function(){
  var _artist = ‘Nelly’;
  this.getArtist = function(){
    return _artist;
  }
});



3) مقدمو الخدمة هم الخدمة الوحيدة التي يمكنك تمريرها في وظيفة .config () الخاصة بك. استخدم موفرًا عندما تريد توفير تكوين على مستوى الوحدة بأكملها لكائن الخدمة قبل إتاحته.

app.controller(‘myProvider’, function($scope, myProvider){
  $scope.artist = myProvider.getArtist();
  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

app.provider(‘myProvider’, function(){
 //Only the next two lines are available in the app.config()
 this._artist = ‘’;
 this.thingFromConfig = ‘’;
  this.$get = function(){
    var that = this;
    return {
      getArtist: function(){
        return that._artist;
      },
      thingOnConfig: that.thingFromConfig
    }
  }
});

app.config(function(myProviderProvider){
  myProviderProvider.thingFromConfig = ‘This was set in config’;
});



غير TL ؛ DR

1) المصنع
تعد المصانع الطريقة الأكثر شيوعًا لإنشاء خدمة وتكوينها. هناك حقا ليس أكثر بكثير مما قاله TL ؛ DR. كل ما عليك هو إنشاء كائن وإضافة خصائص إليه ثم إرجاع نفس الكائن. ثم عند تمرير المصنع إلى وحدة التحكم الخاصة بك ، ستكون تلك الخصائص على الكائن متوفرة الآن في وحدة التحكم هذه من خلال المصنع. مثال أكثر شمولاً هو أدناه.

app.factory(‘myFactory’, function(){
  var service = {};
  return service;
});

الآن سوف تتوفر لنا أي خصائص نعلقها على "الخدمة" عندما نمرر "myFactory" إلى جهاز التحكم الخاص بنا.

الآن دعونا نضيف بعض المتغيرات "الخاصة" إلى وظيفة معاودة الاتصال الخاصة بنا. لن يتم الوصول إلى هذه الأجهزة مباشرة من وحدة التحكم ، ولكننا سنقوم في النهاية بإعداد بعض أساليب getter / setter على 'الخدمة' لنتمكن من تغيير هذه المتغيرات 'الخاصة' عند الحاجة.

app.factory(‘myFactory’, function($http, $q){
  var service = {};
  var baseUrl = ‘https://itunes.apple.com/search?term=’;
  var _artist = ‘’;
  var _finalUrl = ‘’;

  var makeUrl = function(){
   _artist = _artist.split(‘ ‘).join(‘+’);
    _finalUrl = baseUrl + _artist + ‘&callback=JSON_CALLBACK’;
    return _finalUrl
  }

  return service;
});

سوف تلاحظ هنا أننا لا نربط هذه المتغيرات / الوظائف بـ "الخدمة". نحن ببساطة نقوم بإنشائها إما لاستخدامها أو تعديلها فيما بعد.

  • baseUrl هو عنوان URL الأساسي الذي تتطلبه واجهة برمجة تطبيقات iTunes
  • _artist هو الفنان الذي نرغب في البحث عنه
  • _finalUrl هو عنوان URL النهائي والمدمج بالكامل والذي سنجري به الاتصال بـ iTunes
  • makeUrl هي إحدى الوظائف التي ستقوم بإنشاء وإرجاع عنوان URL الخاص بنا على iTunes.

الآن ، وبعد أن أصبحت لدينا وظيفة / متغير ووظيفة خاصة ، دعونا نضيف بعض الخصائص إلى كائن "الخدمة". كل ما نستخدمه في "الخدمة" يمكن استخدامه مباشرة داخل أي جهاز تحكم نمرر به "myFactory".

سننشئ أساليب setArtist و getArtist التي تعيد الفنان أو تعيده. سنقوم أيضًا بإنشاء طريقة تستدعي واجهة برمجة تطبيقات iTunes باستخدام عنوان URL الذي تم إنشاؤه. ستعيد هذه الطريقة وعدًا سيتحقق فور عودة البيانات من واجهة برمجة تطبيقات iTunes. إذا لم تكن لديك خبرة كبيرة باستخدام الوعود في AngularJS ، فإنني أوصي بعمل غوص عميق عليهم.

أدناه setArtist يقبل فنان ويسمح لك بتعيين الفنان. getArtist يعود الفنان. callItunes يقوم أولاً بإجراء makeUrl () لإنشاء عنوان URL الذي سنستخدمه مع طلب http الخاص بنا. ثم يقوم بإعداد كائن الوعد ، ويجعل طلب $ http مع رابط عنوان URL النهائي الخاص بنا ، ثم لأن http $ يعيد الوعد ، فإننا قادرون على الاتصال .success أو .error بعد طلبنا. بعد ذلك نحسم وعدنا باستخدام بيانات iTunes ، أو نرفضها برسالة تقول "حدث خطأ".

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  service.setArtist = function(artist){
    _artist = artist;
  }

  service.getArtist = function(){
    return _artist;
  }

  service.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

  return service;
});

الآن لدينا مصنع كامل. أصبحنا الآن قادرين على حقن "myFactory" في أي وحدة تحكم وسنتمكن بعد ذلك من الاتصال بأساليبنا التي نعلقها على كائن الخدمة لدينا (setArtist و getArtist و callItunes).

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.data = {};
  $scope.updateArtist = function(){
    myFactory.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myFactory.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

في وحدة التحكم أعلاه ، نحن نحقن في خدمة "myFactory". ثم نقوم بتعيين الخصائص على كائن نطاق $ الخاص بنا ببيانات من "myFactory". الرمز الوحيد الوهمي أعلاه هو إذا لم تتعامل مع وعود من قبل. ولأن callItunes يعيد الوعد ، فنحن قادرون على استخدام طريقة .then () ونعين فقط $ scope.data.artistData بمجرد تحقيق وعدنا ببيانات iTunes. ستلاحظ أن جهاز التحكم لدينا "رقيق جدًا" (هذه ممارسة جيدة للترميز). يقع كل من البيانات المنطقية والمستمرة في خدمتنا ، وليس في وحدة تحكم لدينا.

2) الخدمة
ربما يكون أكبر شيء يجب معرفته عند التعامل مع إنشاء خدمة هو أنه تم إنشاء كلمة رئيسية باستخدام الكلمة "الجديدة". بالنسبة لك معلمو جافا سكريبت ، يجب أن يعطيك ذلك تلميحًا كبيرًا في طبيعة الرمز. بالنسبة لمن لديهم خلفية محدودة في JavaScript أو لأولئك الذين ليسوا على دراية تامة بما تفعله الكلمة الرئيسية "الجديدة" بالفعل ، دعنا نراجع بعض أساسيات JavaScript التي ستساعدنا في النهاية في فهم طبيعة الخدمة.

ولرؤية التغييرات التي تحدث عند استدعاء دالة باستخدام الكلمة الأساسية "الجديدة" ، دعنا ننشئ وظيفة ونستدعيها باستخدام الكلمة الرئيسية "الجديدة" ، ثم دعنا نعرض ما يفعله المترجم عندما يرى الكلمة الرئيسية "الجديدة". ستكون النتائج النهائية هي نفسها.

دعونا أولا إنشاء المنشئ لدينا.

var Person = function(name, age){
  this.name = name;
  this.age = age;
}

هذه وظيفة منشئ جافا سكريبت نموذجية. الآن عندما نستدعي وظيفة الشخص باستخدام الكلمة الأساسية "الجديدة" ، سيكون "هذا" مرتبطًا بالعنصر الذي تم إنشاؤه حديثًا.

الآن دعونا نضيف طريقة إلى النموذج الأولي للشخص حتى يكون متاحًا في كل حالة من صنف الشخص.

Person.prototype.sayName = function(){
  alert(‘My name is ‘ + this.name);
}

الآن ، نظرًا لأننا وضعنا الدالة sayName على النموذج الأولي ، فسيكون بإمكان كل شخص من الأشخاص الاتصال بوظيفة sayName لتنبيه اسم هذا المثل.

الآن بعد أن أصبح لدينا وظيفة منشئ الشخص ووظيفة sayName على نموذجه الأولي ، دعنا في الواقع ننتج مثيل لشخص ثم نطلق على الدالة sayName.

var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’

لذلك كل ذلك معا رمز لإنشاء المنشئ الشخص ، إضافة وظيفة إلى النموذج الأولي ، وإنشاء مثيل شخص ، ومن ثم استدعاء الدالة على النموذج الأولي يشبه هذا.

var Person = function(name, age){
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function(){
  alert(‘My name is ‘ + this.name);
}
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’

الآن دعنا نلقي نظرة على ما يحدث في الواقع عند استخدام الكلمة الأساسية "الجديدة" في JavaScript. أول شيء يجب أن تلاحظه هو أنه بعد استخدام "جديد" في مثالنا ، يمكننا الاتصال بطريقة (sayName) على "tyler" تمامًا كما لو كان كائنًا - وهذا هو السبب في ذلك. أولاً ، نعرف أن شخصنا المنشئ يعيد شيئًا ، سواء أمكننا رؤية ذلك في الكود أم لا. ثانيًا ، نعلم أنه نظرًا لأن وظيفة sayName تقع على النموذج الأولي وليس مباشرة على مثيل الشخص ، فيجب أن يتم تفويض الكائن الذي تعود إليه وظيفة الشخص إلى النموذج الأولي في عمليات البحث الفاشلة. بعبارات أكثر بساطة ، عندما نسمي tyler.sayName () ، يقول المترجم "حسناً ، سأقوم بالبحث عن كائن" tyler "الذي أنشأناه للتو ، وحدد موقع الدالة sayName ، ثم اتصل به. انتظر لحظة ، وأنا لا أرى ذلك هنا - كل ما أراه هو الاسم والعمر ، اسمحوا لي أن تحقق من النموذج الأولي. نعم ، يبدو أنه على النموذج الأولي ، دعني أطلق عليه. ".

فيما يلي كود لكيفية التفكير في ما تقوم به الكلمة الرئيسية "الجديدة" بالفعل في JavaScript. انها في الاساس مثال رمز للفقرة أعلاه. لقد وضعت "عرض مترجم" أو الطريقة التي يرى بها المترجم الشفرة داخل الملاحظات.

var Person = function(name, age){
  //The below line creates an object(obj) that will delegate to the person’s prototype on failed lookups.
  //var obj = Object.create(Person.prototype);

  //The line directly below this sets ‘this’ to the newly created object
  //this = obj;

  this.name = name;
  this.age = age;

  //return this;
}

والآن بعد أن اكتسبت هذه المعرفة ما تعنيه الكلمة الأساسية "الجديدة" بالفعل في جافا سكريبت ، يجب أن يكون إنشاء خدمة في AngularJS أسهل في الفهم.

أكبر شيء يجب فهمه عند إنشاء الخدمة هو معرفة أن الخدمات يتم إنشاؤها باستخدام الكلمة الأساسية "الجديدة". بدمج تلك المعرفة مع الأمثلة المذكورة أعلاه ، يجب عليك الآن أن تدرك أنك سترفق خصائصك وأساليبك مباشرة إلى "هذا" ، والتي ستتم إعادتها من الخدمة نفسها. دعونا نلقي نظرة على هذا في العمل.

على عكس ما فعلناه في الأصل مع مثال المصنع ، لا نحتاج إلى إنشاء كائن ثم نعيد هذا الكائن لأنه ، مثلما ذكرنا مرات عديدة من قبل ، استخدمنا الكلمة الرئيسية "الجديدة" بحيث ينشئ المترجم ذلك الكائن ، أو يفوضه إنه نموذج أولي ، ثم أعيده لنا بدون الاضطرار إلى القيام بالعمل.

أول الأشياء أولاً ، دعنا ننشئ وظيفتنا "الخاصة" و المساعدة. هذا يجب أن تبدو مألوفة للغاية لأننا فعلنا نفس الشيء بالضبط مع مصنعنا. لن أفسر ما يفعله كل سطر هنا لأنني فعلت ذلك في مثال المصنع ، إذا كنت مرتبكًا ، فأعد قراءة مثال المصنع.

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
});

الآن ، سنقوم بإرفاق جميع طرقنا التي ستكون متاحة في جهاز التحكم لدينا إلى "هذا".

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.setArtist = function(artist){
    _artist = artist;
  }

  this.getArtist = function(){
    return _artist;
  }

  this.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

});

الآن تمامًا كما هو الحال في المصنع ، سيتوفر كل من setArtist و getArtist و callItunes في أي جهاز تحكم نمرر فيه خدمة myService. وهنا تحكم myService (وهو تقريبا نفس وحدة تحكم المصنع).

app.controller('myServiceCtrl', function($scope, myService){
  $scope.data = {};
  $scope.updateArtist = function(){
    myService.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myService.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

كما ذكرت من قبل ، بمجرد أن تفهم حقا ما هو "الجديد" ، فإن الخدمات تكاد تكون متطابقة مع المصانع في AngularJS.

3) مقدم

أكبر شيء يجب تذكره عن مقدمي الخدمة هو أنها الخدمة الوحيدة التي يمكنك نقلها إلى جزء التطبيق app.config من التطبيق الخاص بك. يعتبر هذا الأمر ذا أهمية كبيرة إذا كنت تحتاج إلى تغيير جزء من عنصر الخدمة قبل أن يكون متاحًا في أي مكان آخر في تطبيقك. على الرغم من أنها مشابهة جدًا للخدمات / المصانع ، إلا أن هناك بعض الاختلافات التي سنناقشها.

أولاً قمنا بإعداد مقدم الخدمة بطريقة مماثلة مع خدمتنا ومصنعنا. المتغيرات أدناه هي وظيفتنا "الخاصة" و المساعد.

app.provider('myProvider', function(){
   var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  //Going to set this property on the config function below.
  this.thingFromConfig = ‘’;

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
}

* مرة أخرى إذا كان هناك أي جزء من الشفرة المذكورة أعلاه مربكًا ، فاطلع على قسم المصنع حيث أشرح ما يفعله جميعًا بتفاصيل أكبر.

يمكنك التفكير في مزودي الخدمة على أنهم ثلاثة أقسام. القسم الأول هو المتغيرات / الوظائف "الخاصة" التي سيتم تعديلها / تعيينها لاحقًا (كما هو موضح أعلاه). القسم الثاني هو المتغيرات / الوظائف التي ستكون متاحة في وظيفة app.config الخاصة بك ، وبالتالي فهي متاحة للتغيير قبل أن تكون متوفرة في أي مكان آخر (كما هو موضح أعلاه). من المهم ملاحظة أنه يجب إرفاق تلك المتغيرات بالكلمة الرئيسية "هذه". في مثالنا ، لن يتوفر سوى "thingFromConfig" للتغيير في app.config. القسم الثالث (كما هو موضح أدناه) هو جميع المتغيرات / الوظائف التي ستكون متاحة في وحدة التحكم الخاصة بك عندما تمر في خدمة "myProvider" إلى وحدة التحكم المحددة.

عند إنشاء خدمة مع الموفر ، فإن الخصائص / الطرق الوحيدة المتوفرة في وحدة التحكم هي تلك الخصائص / الأساليب التي يتم إرجاعها من دالة $ get (). الرمز أدناه يضع $ get على "هذا" (الذي نعرف أنه سيعود في النهاية من تلك الوظيفة). الآن ، تقوم وظيفة get $ بإرجاع كافة الطرق / الخصائص التي نريد أن تكون متوفرة في وحدة التحكم. هنا مثال الكود.

this.$get = function($http, $q){
    return {
      callItunes: function(){
        makeUrl();
        var deferred = $q.defer();
        $http({
          method: 'JSONP',
          url: _finalUrl
        }).success(function(data){
          deferred.resolve(data);
        }).error(function(){
          deferred.reject('There was an error')
        })
        return deferred.promise;
      },
      setArtist: function(artist){
        _artist = artist;
      },
      getArtist: function(){
        return _artist;
      },
      thingOnConfig: this.thingFromConfig
    }
  }

الآن يبدو رمز الموفر الكامل كهذا

app.provider('myProvider', function(){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  //Going to set this property on the config function below
  this.thingFromConfig = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.$get = function($http, $q){
    return {
      callItunes: function(){
        makeUrl();
        var deferred = $q.defer();
        $http({
          method: 'JSONP',
          url: _finalUrl
        }).success(function(data){
          deferred.resolve(data);
        }).error(function(){
          deferred.reject('There was an error')
        })
        return deferred.promise;
      },
      setArtist: function(artist){
        _artist = artist;
      },
      getArtist: function(){
        return _artist;
      },
      thingOnConfig: this.thingFromConfig
    }
  }
});

الآن تمامًا كما هو الحال في المصنع والخدمة ، سيتوفر كل من setArtist و getArtist و callItunes في أي وحدة تحكم نمرر فيها myProvider. وهنا تحكم myProvider (وهو تقريبا نفس وحدة تحكم المصنع / الخدمة).

app.controller('myProviderCtrl', function($scope, myProvider){
  $scope.data = {};
  $scope.updateArtist = function(){
    myProvider.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myProvider.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }

  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

كما ذكرنا من قبل ، فإن الهدف الكامل من إنشاء خدمة مع الموفر هو القدرة على تغيير بعض المتغيرات من خلال وظيفة app.config قبل تمرير الكائن النهائي إلى باقي التطبيق. دعونا نرى مثالا على ذلك.

app.config(function(myProviderProvider){
  //Providers are the only service you can pass into app.config
  myProviderProvider.thingFromConfig = 'This sentence was set in app.config. Providers are the only service that can be passed into config. Check out the code to see how it works';
});

الآن يمكنك أن ترى كيف أن "thingFromConfig" عبارة عن سلسلة فارغة في مزودنا ، ولكن عندما يظهر ذلك في DOM ، سيكون "تم تعيين هذه الجملة ...".


فهم AngularJS مصنع وخدمة ومقدم

كل هذه تستخدم لتبادل الكائنات singleton قابلة لإعادة الاستخدام. يساعدك على مشاركة التعليمات البرمجية القابلة لإعادة الاستخدام عبر تطبيقك / مكونات / وحدات متعددة.

من Service/Factory المستندات Service/Factory :

  • تم إنشاء مثيل زاوي - يقوم Angular فقط بإنشاء خدمة / مصنع عندما يعتمد مكون التطبيق على ذلك.
  • Singletons - يحصل كل مكون معتمد على خدمة على مرجع إلى المثيل المفرد الناتج عن مصنع الخدمة.

مصنع

مصنع هو وظيفة حيث يمكنك معالجة / إضافة المنطق قبل إنشاء كائن ، ثم يتم إرجاع الكائن الذي تم إنشاؤه حديثًا.

app.factory('MyFactory', function() {
    var serviceObj = {};
    //creating an object with methods/functions or variables
    serviceObj.myFunction = function() {
        //TO DO:
    };
    //return that object
    return serviceObj;
});

استعمال

يمكن أن يكون مجرد مجموعة من الوظائف مثل الصف.وبالتالي ، يمكن إنشاء مثيل له في وحدات تحكم مختلفة عندما تقوم بحقنه داخل وظائف وحدة التحكم / المصنع / التوجيه. يتم إنشاء مثيله مرة واحدة فقط لكل تطبيق.

الخدمات

ببساطة أثناء النظر إلى الخدمات فكر في النموذج الأولي للمجموعة. الخدمة هي وظيفة تقوم بإنشاء كائن جديد باستخدام الكلمة الأساسية "الجديدة". يمكنك إضافة خصائص ووظائف إلى كائن خدمة باستخدام thisالكلمة الأساسية. على عكس المصنع ، فإنه لا يعيد أي شيء (يقوم بإرجاع كائن يحتوي على طرق / خصائص).

app.service('MyService', function() {
    //directly binding events to this context
    this.myServiceFunction = function() {
        //TO DO:
    };
});

استعمال

استخدامه عندما تحتاج إلى مشاركة كائن واحد في جميع أنحاء التطبيق. على سبيل المثال ، تفاصيل المستخدم المصادق عليها ، والأساليب / البيانات التي يمكن مشاركتها ، ووظائف المساعدة ، إلخ.

مزود

يتم استخدام موفر لإنشاء كائن خدمة قابل للتكوين. يمكنك تكوين إعداد الخدمة من وظيفة التهيئة. تقوم بإرجاع قيمة باستخدام $get()الدالة. و $getيعدم الدالة على مرحلة التشغيل في الزاوي.

app.provider('configurableService', function() {
    var name = '';
    //this method can be be available at configuration time inside app.config.
    this.setName = function(newName) {
        name = newName;
    };
    this.$get = function() {
        var getName = function() {
             return name;
        };
        return {
            getName: getName //exposed object to where it gets injected.
        };
    };
});

استعمال

عندما تحتاج إلى توفير تهيئة وحدة نمطية لكائن الخدمة قبل إتاحتها ، على سبيل المثال. لنفترض أنك تريد تعيين عنوان URL API الخاص بك على أساس البيئة الخاصة بك مثل dev، stageأوprod

ملحوظة

سيكون المزود الوحيد متاحًا في مرحلة التهيئة للزاوية ، بينما لا تكون الخدمة والمصانع كذلك.

آمل أن يكون هذا قد أوضح فهمك حول المصنع والخدمة والموفر .


مقابل خدمة مزود مقابل المصنع:

أحاول أن أبقيه بسيطًا. كل شيء عن مفهوم جافا سكريبت الأساسي.

أولا وقبل كل شيء ، دعونا نتحدث عن الخدمات في AngularJS!

ما هي الخدمة: في AngularJS ، الخدمةليس سوى كائن جافا سكريبت المفرد الذي يمكنه تخزين بعض الأساليب أو الخصائص المفيدة. يتم إنشاء هذا الكائن المفرد لكل أساس ngApp (التطبيق الزاوي) ويتم مشاركته بين جميع وحدات التحكم في التطبيق الحالي. عندما يقوم Angularjs بإنشاء كائن خدمة ، فإنه يقوم بتسجيل كائن الخدمة هذا باسم خدمة فريد. لذلك في كل مرة نحتاج فيها إلى مثيل خدمة ، يقوم Angular بالبحث في السجل عن اسم الخدمة هذا ، ويعيد المرجع إلى كائن الخدمة. بحيث يمكننا استدعاء الأسلوب ، وخصائص الوصول وما إلى ذلك على كائن الخدمة. قد يكون لديك سؤال ما إذا كان يمكنك أيضا وضع خصائص ، وأساليب على كائن نطاق وحدات تحكم! لذلك لماذا تحتاج إلى كائن الخدمة؟ الإجابات هي: يتم مشاركة الخدمات بين نطاق وحدة تحكم متعددة. إذا وضعت بعض الخصائص / الأساليب في كائن نطاق وحدة التحكم ، فسيكون متاحًا للنطاق الحالي فقط.ولكن عندما تقوم بتعريف أساليب ، خصائص على كائن خدمة ، ستكون متاحة عالمياً ويمكن الوصول إليها في نطاق أي وحدة تحكم عن طريق حقن تلك الخدمة.

حتى إذا كان هناك ثلاثة نطاق وحدة تحكم ، فليكن يكون controllerA ، controllerB و controllerC ، كل مشاركة نفس مثيل الخدمة.

<div ng-controller='controllerA'>
    <!-- controllerA scope -->
</div>
<div ng-controller='controllerB'>
    <!-- controllerB scope -->
</div>
<div ng-controller='controllerC'>
    <!-- controllerC scope -->
</div>

كيف تصنع خدمة؟

تقدم AngularJS طرقًا مختلفة لتسجيل الخدمة. هنا سوف نركز على ثلاث طرق المصنع (..) ، الخدمة (..) ، مزود (..) ؛

استخدم هذا الرابط كمرجع رمز

وظيفة المصنع:

يمكننا تحديد وظيفة مصنع على النحو التالي.

factory('serviceName',function fnFactory(){ return serviceInstance;})

يوفر AngularJS 'factory (' serviceName '، fnFactory)' method الذي يأخذ معلمتين و serviceName ووظيفة JavaScript. الزاوي يخلق خدمة سبيل المثال عن طريق استدعاء الدالة fnFactory () مثل أدناه.

var serviceInstace = fnFactory();

يمكن للدالة التي تم تمريرها تعريف كائن وإرجاع هذا الكائن. AngularJS ببساطة يخزن مرجع الكائن هذا إلى متغير يتم تمريره كوسيطة أولى. أي شيء يتم إرجاعه من fnFactory سيتم ربطه بالخدمات. بدلاً من إرجاع الكائن ، يمكننا أيضاً إرجاع الدالة والقيم إلخ ، مهما كان ما سيعود ، ستكون متوفرة لمثيل الخدمة.

مثال:

var app= angular.module('myApp', []);
//creating service using factory method
app.factory('factoryPattern',function(){
  var data={
    'firstName':'Tom',
    'lastName':' Cruise',
    greet: function(){
      console.log('hello!' + this.firstName + this.lastName);
    }
  };

  //Now all the properties and methods of data object will be available in our service object
  return data;
});

وظيفة الخدمة:

service('serviceName',function fnServiceConstructor(){})

إنها طريقة أخرى ، يمكننا تسجيل الخدمة. الاختلاف الوحيد هو الطريقة التي يحاول AngularJS إنشاء كائن الخدمة. تستخدم هذه الزاوية الزاويّة كلمة "جديدة" وتستدعي الدالة المنشئة شيئًا مثل أدناه.

var serviceInstance = new fnServiceConstructor();

في دالة المُنشئ ، يمكننا استخدام كلمة "this" هذه لإضافة خصائص / طرق إلى كائن الخدمة. مثال:

//Creating a service using the service method
var app= angular.module('myApp', []);
app.service('servicePattern',function(){
  this.firstName ='James';
  this.lastName =' Bond';
  this.greet = function(){
    console.log('My Name is '+ this.firstName + this.lastName);
  };
});

وظيفة مزود:

وظيفة موفر () هي طريقة أخرى لإنشاء الخدمات. دعنا مهتمين بإنشاء خدمة تعرض فقط بعض رسائل الترحيب للمستخدم. ولكننا نريد أيضًا توفير وظيفة بحيث يمكن للمستخدم تعيين رسالة الترحيب الخاصة به. من الناحية الفنية ، نريد إنشاء خدمات قابلة للتهيئة. كيف يمكننا عمل ذلك ؟ يجب أن يكون هناك طريقة ، بحيث يمكن لهذا التطبيق تمرير رسائل التهنئة المخصصة له ، وستجعل Angularjs متاحًا لوظيفة المصنع / المُنشئ التي تنشئ مثيل خدماتنا. في مثل هذه الحالة مزود () وظيفة تقوم بهذه المهمة. باستخدام مزود () وظيفة يمكننا إنشاء خدمات شكلي.

يمكننا إنشاء خدمات قابلة للتكوين باستخدام بنية موفر الخدمة كما هو موضح أدناه.

/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});

/*step2:configure the service */
app.config(function configureService(serviceProvider){});

كيف يعمل بناء على موفر الخدمة داخليا؟

يتم إنشاء كائن 1.Provider باستخدام وظيفة منشئ قمنا بتعريفها في وظيفة مزود لدينا.

var serviceProvider = new serviceProviderConstructor();

2. وظيفة مررنا في app.config () ، الحصول على تنفيذها. هذا ما يسمى مرحلة التهيئة ، وهنا لدينا فرصة لتخصيص خدمتنا.

configureService(serviceProvider);

يتم إنشاء 3.Finally خدمة مثيل من خلال استدعاء أسلوب $ get من serviceProvider.

serviceInstance = serviceProvider.$get()

نموذج كود لإنشاء خدمة باستخدام بناء الجملة:

var app= angular.module('myApp', []);
app.provider('providerPattern',function providerConstructor(){
  //this function works as constructor function for provider
  this.firstName = 'Arnold ';
  this.lastName = ' Schwarzenegger' ;
  this.greetMessage = ' Welcome, This is default Greeting Message' ;
  //adding some method which we can call in app.config() function
  this.setGreetMsg = function(msg){
    if(msg){
      this.greetMessage =  msg ;
    }
  };

  //We can also add a method which can change firstName and lastName
  this.$get = function(){
    var firstName = this.firstName;
    var lastName = this.lastName ;
    var greetMessage = this.greetMessage;
    var data={
       greet: function(){
         console.log('hello, ' + firstName + lastName+'! '+ greetMessage);
       }
    };
    return data ;
  };
});

app.config(
  function(providerPatternProvider){
    providerPatternProvider.setGreetMsg(' How do you do ?');
  }
);

العمل التجريبي

ملخص:

مصنع استخدام وظيفة المصنع الذي يعود مثيل خدمة. serviceInstance = fnFactory ()؛

تستخدم الخدمة وظيفة منشئ ، وتستدعي Angular وظيفة المنشيء باستخدام الكلمة الرئيسية "الجديدة" لإنشاء نسخة الخدمة. serviceInstance = new fnServiceConstructor ()؛

مزود يحدد وظيفة providerConstructor، وتعرف هذه الوظيفة providerConstructor وظيفة مصنع $ الحصول على . مكالمات Angular $ get () لإنشاء كائن الخدمة. يحتوي بناء جملة الموفر على ميزة إضافية لتكوين كائن الخدمة قبل أن يتم إنشاء مثيل له. serviceInstance = $ get ()؛


بعد قراءة كل هذه الوظائف خلقت المزيد من الخلط بالنسبة لي .. ولكن لا يزال كل شيء يستحق معلومات .. وأخيرا وجدت الجدول التالي الذي سيعطي المعلومات مع المقارنة بسيطة

  • يستخدم الحاقن الوصفات لإنشاء نوعين من الكائنات: الخدمات وكائنات الأغراض الخاصة
  • هناك خمسة أنواع من الوصفات التي تحدد كيفية إنشاء الكائنات: القيمة ، المصنع ، الخدمة ، المزود والمستمر.
  • المصنع والخدمة هي الوصفات الأكثر استخدامًا. والفرق الوحيد بينهما هو أن وصفة الخدمة تعمل بشكل أفضل لكائنات من نوع مخصص ، في حين أن المصنع يمكن أن ينتج مواد ووظائف JavaScript.
  • وصفة الموفر هي نوع الوصفة الأساسية ، وجميع الوصفات الأخرى هي سكر نحوي فقط.
  • الموفر هو نوع الوصفة الأكثر تعقيدًا. لا تحتاج إليها إلا إذا كنت تقوم ببناء جزء من التعليمات البرمجية التي يمكن إعادة استخدامها والتي تحتاج إلى تكوين عالمي.
  • يتم تعريف جميع الأغراض ذات الأغراض الخاصة باستثناء وحدة التحكم عن طريق وصفات المصنع.

وللمفهوم المبتدئ: - قد لا يصحح ذلك حالة الاستخدام ولكن في المستوى المرتفع هذا هو ما يمكن استخدامه لهؤلاء الثلاثة.

  1. إذا كنت ترغب في استخدامها في وظيفة التكوين وحدة الزاوي يجب إنشاء كمزود

angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})

  1. يجب أن تكون خدمة Ajax call أو تكامل الطرف الثالث خدمة .
  2. بالنسبة إلى معالجات البيانات ، يمكنك إنشائها كمصنع

بالنسبة لسلوك وتصميمات السيناريوهات الأساسية ، فإنها تتصرف بنفس الطريقة.


توضيحي حول هذه المسألة:

أساسا جميع الأنواع المذكورة (خدمة ، مصنع ، مزود ، الخ) هي مجرد إنشاء وتكوين المتغيرات العالمية (التي هي بالطبع عالمية إلى التطبيق بأكمله) ، تماما كما كانت المتغيرات العالمية القديمة.

على الرغم من أن المتغيرات العالمية غير مستحسنة ، إلا أن الاستخدام الحقيقي لهذه المتغيرات العامة هو توفير الحقن التبعية ، عن طريق تمرير المتغير إلى وحدة التحكم ذات الصلة.

هناك العديد من مستويات المضاعفات في إنشاء قيم "المتغيرات العالمية":

  1. ثابت
    يحدد هذا ثابتًا فعليًا لا يجب تعديله أثناء التطبيق بالكامل ، تمامًا مثل الثوابت في اللغات الأخرى (شيء تفتقر إليه جافا سكريبت).
  2. القيمة
    هذه قيمة أو عنصر قابل للتعديل ، وهي بمثابة متغير عالمي ، يمكن حقنه حتى عند إنشاء خدمات أو مصانع أخرى (انظر المزيد عن ذلك). ومع ذلك ، يجب أن تكون " قيمة حرفية " ، مما يعني أن على المرء أن يكتب القيمة الفعلية ، ولا يمكنه استخدام أي منطق حساب أو برمجة (بمعنى آخر 39 أو myText أو {prop: "value"} لا بأس بها ، ولكن 2 + 2 ليس).
  3. مصنع
    قيمة أكثر عمومية ، يمكن حسابها على الفور. يعمل عن طريق تمرير دالة إلى AngularJS مع المنطق المطلوب لحساب القيمة ويقوم AngularJS بتنفيذها ، ويقوم بحفظ قيمة الإرجاع في المتغير المحدد.
    لاحظ أنه من الممكن إرجاع كائن (في هذه الحالة سوف يعمل بشكل مشابه للخدمة ) أو دالة (سيتم حفظها في المتغير كوظيفة رد اتصال).
  4. الخدمات
    الخدمة هي نسخة أكثر تجريدًا من المصنع تكون صالحة فقط عندما تكون القيمة كائنًا ، وتسمح لكتابة أي منطق بشكل مباشر في الوظيفة (كما لو كان مُنشئًا) ، بالإضافة إلى الإعلان والوصول إلى خصائص الكائن باستخدام هذه الكلمة.
  5. مقدم
    الخدمة على عكس الخدمة التي هي نسخة مبسطة من المصنع ، فإن مقدم الخدمة هو طريقة أكثر تعقيدًا ، ولكنها أكثر مرونة لتهيئة المتغيرات "العالمية" ، مع أكبر مرونة هي خيار تعيين القيم من app.config.
    وهي تعمل مثل باستخدام مزيج من الخدمة و مزود ، عن طريق تمرير إلى مزود وظيفة الذي له خصائص أعلنت باستخدام هذه الكلمة، والتي يمكن استخدامها من app.config.
    ثم تحتاج إلى وظيفة منفصلة .get يتم تنفيذها بواسطة AngularJS بعد إعداد الخصائص أعلاه عبر app.configالملف ، وهذه الوظيفة $get تعمل كما هو الحال في المصنع أعلاه ، حيث يتم استخدام قيمة الإرجاع الخاصة به لتهيئة المتغيرات "العمومية".

لاحظت شيئًا مثيرًا للاهتمام عند اللعب مع مقدمي الخدمة.

إن رؤية الحقن تختلف بالنسبة لمقدمي الخدمات عن الخدمات والمصانع. إذا قمت بالإعلان عن "ثابت" AngularJS (على سبيل المثال ، myApp.constant('a', 'Robert');) ، يمكنك حقنه في الخدمات والمصانع ومزودي الخدمة.

ولكن إذا قمت بالإعلان عن "قيمة" AngularJS (على سبيل المثال. ، myApp.value('b', {name: 'Jones'});) ، يمكنك حقنها في الخدمات والمصانع ، ولكن ليس في وظيفة إنشاء الموفر. ومع ذلك ، يمكنك حقنه في $getالوظيفة التي تحددها لمزودك. هذا مذكور في وثائق AngularJS ، ولكن من السهل أن تفوتك. يمكنك العثور عليه في صفحة٪ تقديم في الأقسام على القيمة والطرق الثابتة.

http://jsfiddle.net/R2Frv/1/

<div ng-app="MyAppName">
    <div ng-controller="MyCtrl">
        <p>from Service: {{servGreet}}</p>
        <p>from Provider: {{provGreet}}</p>
    </div>
</div>
<script>
    var myApp = angular.module('MyAppName', []);

    myApp.constant('a', 'Robert');
    myApp.value('b', {name: 'Jones'});

    myApp.service('greetService', function(a,b) {
        this.greeter = 'Hi there, ' + a + ' ' + b.name;
    });

    myApp.provider('greetProvider', function(a) {
        this.firstName = a;
        this.$get = function(b) {
            this.lastName = b.name;
            this.fullName = this.firstName + ' ' + this.lastName;
            return this;
        };
    });

    function MyCtrl($scope, greetService, greetProvider) {
        $scope.servGreet = greetService.greeter;
        $scope.provGreet = greetProvider.fullName;
    }
</script>

ما أفهمه بسيط للغاية أدناه.

المصنع: يمكنك ببساطة إنشاء كائن داخل المصنع وإعادته.

الخدمات:

لديك فقط وظيفة قياسية تستخدم هذه الكلمة الرئيسية لتعريف وظيفة.

مزود:

هناك $getكائن قمت بتعريفه ويمكن استخدامه للحصول على الكائن الذي يقوم بإرجاع البيانات.


هذه الإجابة تتناول الموضوع / السؤال

كيف المصنع والخدمة والثابتة - هي مجرد السكر النحوي على رأس وصفة مقدم؟

أو

كيف يتم مصنع ، servic وموفري simailar داخليا

أساسا ما يحدث هو

عندما تقوم factory()بإعدادها ، تقوم functionبتعيينها في وسيطة ثانية إلى الموفر $getوإرجاعها ( provider(name, {$get:factoryFn })) ، كل ما تحصل عليه هو providerليس هناك خاصية / طريقة أخرى غير$get ذلك provider(يعني أنه لا يمكنك تكوين ذلك)

كود المصدر من المصنع

function factory(name, factoryFn, enforce) {
    return provider(name, {
      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
    });
};

عندما تقوم service()بإرجاعها تقوم بتوفير مصنع () مع ذلك functionالذي يقوم بحقن constructor(إرجاع مثيل المنشئ الذي قدمته في خدمتك) وإعادته

كود مصدر الخدمة

function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
};

إذاً في الأساس في كلتا الحالتين ، تحصل في نهاية المطاف على موفري $ يتم تعيينهم على وظيفتك التي قدمتها ، ولكن يمكنك إعطاء أي شيء أكثر من $ get كما يمكنك توفيره في الأصل في موفر () لكتلة config


هناك إجابات جيدة بالفعل ، لكني أريد فقط مشاركة هذه الإجابة.

أولاً: الموفر هو الطريقة / الوصفة لإنشاء service(كائن مفرد) الذي يفترض أن يتم حقنه بواسطة حاقن $ (كيف تنتقل AngulaJS عن نمط IoC).

و القيمة، مصنع، خدمة وثابت (4 طرق) - السكر النحوي على مزود الطريق / recepie.

هناك Service vs Factoryجزء تم تغطيته: https://www.youtube.com/watch?v=BLzNCkPn3ao

الخدمةnew تدور حول الكلمة الرئيسية في الواقع والتي كما نعلم 4 أشياء:

  1. يخلق كائن جديد
  2. يربطها إلى prototypeكائنها
  3. يربط contextلthis
  4. ويعود this

و مصنع هو كل شيء عن نمط مصنع - يحتوي على وظائف التي ترجع كائنات مثل تلك الخدمة.

  1. القدرة على استخدام خدمات أخرى (لديها تبعيات)
  2. تهيئة الخدمة
  3. التهيئة المتأخرة / البطيئة

وهذا فيديو بسيط / قصير: يغطي أيضا مزود : https://www.youtube.com/watch?v=HvTZbQ_hUZY (هناك ترى سترى كيف يذهبون من المصنع إلى مزود)

يتم استخدام وصفة الموفر في الغالب في تهيئة التطبيق ، قبل بدء التطبيق بشكل كامل / تهيئة.


أساسا ، مزود ، مصنع ، وخدمة جميع الخدمات. المصنع هو حالة خاصة من الخدمة عندما تكون كل ما تحتاج إليه هو وظيفة get $ ($ get) ، مما يسمح لك بكتابتها برمز أقل.

الاختلافات الرئيسية بين الخدمات والمصانع ومزودي الخدمة هي تعقيداتهم. الخدمات هي أبسط أشكالها ، والمصانع أكثر قوة ، ومقدمو الخدمات قابلون للتهيئة في وقت التشغيل.

في ما يلي ملخص عن وقت استخدام كل منها:

المصنع : يجب احتساب القيمة التي تقدمها وفقًا للبيانات الأخرى.

الخدمة : تقوم بإرجاع كائن بالطرق.

الموفر : تريد أن تكون قادرًا على تكوين ، خلال مرحلة التكوين ، الكائن الذي سيتم إنشاؤه قبل إنشائه. استخدم الموفر في الغالب في تهيئة التطبيق ، قبل تهيئة التطبيق بشكل كامل.


أعرف الكثير من الإجابات الممتازة ولكن يجب أن أشارك تجربتي في استخدام
1. serviceلمعظم حالات التخلف
2. factoryالمستخدمة في إنشاء الخدمة تلك المثالية

// factory.js ////////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .factory('xFactory', xFactoryImp);
xFactoryImp.$inject = ['$http'];

function xFactoryImp($http) {
    var fac = function (params) {
        this._params = params; // used for query params
    };

    fac.prototype.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }
    return fac;
}
})();

// service.js //////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .service('xService', xServiceImp);
xServiceImp.$inject = ['$http'];

function xServiceImp($http) {  
    this._params = {'model': 'account','mode': 'list'};

    this.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }       
}
})();

واستخدام:

controller: ['xFactory', 'xService', function(xFactory, xService){

        // books = new instance of xFactory for query 'book' model
        var books = new xFactory({'model': 'book', 'mode': 'list'});

        // accounts = new instance of xFactory for query 'accounts' model
        var accounts = new xFactory({'model': 'account', 'mode': 'list'});

        // accounts2 = accounts variable
        var accounts2 = xService;
... 

باستخدام هذه الصفحة docs.angularjs.org/guide/providers (التي يبدو أنها تحسنت بشكل كبير منذ آخر مرة نظرت فيها) ، قمت بتجميع العرض التوضيحي العالمي الحقيقي التالي (-) الذي يستخدم 4 من أصل 5 نكهات لمزود الخدمة. القيمة ، ثابت ، مصنع وموفر في مهب كاملة.

HTML:

<div ng-controller="mainCtrl as main">
    <h1>{{main.title}}*</h1>
    <h2>{{main.strapline}}</h2>
    <p>Earn {{main.earn}} per click</p>
    <p>You've earned {{main.earned}} by clicking!</p>
    <button ng-click="main.handleClick()">Click me to earn</button>
    <small>* Not actual money</small>
</div>

التطبيق

var app = angular.module('angularProviders', []);

// A CONSTANT is not going to change
app.constant('range', 100);

// A VALUE could change, but probably / typically doesn't
app.value('title', 'Earn money by clicking');
app.value('strapline', 'Adventures in ng Providers');

// A simple FACTORY allows us to compute a value @ runtime.
// Furthermore, it can have other dependencies injected into it such
// as our range constant.
app.factory('random', function randomFactory(range) {
    // Get a random number within the range defined in our CONSTANT
    return Math.random() * range;
});

// A PROVIDER, must return a custom type which implements the functionality 
// provided by our service (see what I did there?).
// Here we define the constructor for the custom type the PROVIDER below will 
// instantiate and return.
var Money = function(locale) {

    // Depending on locale string set during config phase, we'll
    // use different symbols and positioning for any values we 
    // need to display as currency
    this.settings = {
        uk: {
            front: true,
            currency: '£',
            thousand: ',',
            decimal: '.'
        },
        eu: {
            front: false,
            currency: '€',
            thousand: '.',
            decimal: ','
        }
    };

    this.locale = locale;
};

// Return a monetary value with currency symbol and placement, and decimal 
// and thousand delimiters according to the locale set in the config phase.
Money.prototype.convertValue = function(value) {

    var settings = this.settings[this.locale],
        decimalIndex, converted;

    converted = this.addThousandSeparator(value.toFixed(2), settings.thousand);

    decimalIndex = converted.length - 3;

    converted = converted.substr(0, decimalIndex) +
        settings.decimal +
        converted.substr(decimalIndex + 1);    

    converted = settings.front ?
            settings.currency + converted : 
            converted + settings.currency; 

    return converted;   
};

// Add supplied thousand separator to supplied value
Money.prototype.addThousandSeparator = function(value, symbol) {
   return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, symbol);
};

// PROVIDER is the core recipe type - VALUE, CONSTANT, SERVICE & FACTORY
// are all effectively syntactic sugar built on top of the PROVIDER construct
// One of the advantages of the PROVIDER is that we can configure it before the
// application starts (see config below).
app.provider('money', function MoneyProvider() {

    var locale;

    // Function called by the config to set up the provider
    this.setLocale = function(value) {
        locale = value;   
    };

    // All providers need to implement a $get method which returns
    // an instance of the custom class which constitutes the service
    this.$get = function moneyFactory() {
        return new Money(locale);
    };
});

// We can configure a PROVIDER on application initialisation.
app.config(['moneyProvider', function(moneyProvider) {
    moneyProvider.setLocale('uk');
    //moneyProvider.setLocale('eu'); 
}]);

// The ubiquitous controller
app.controller('mainCtrl', function($scope, title, strapline, random, money) {

    // Plain old VALUE(s)
    this.title = title;
    this.strapline = strapline;

    this.count = 0;

    // Compute values using our money provider    
    this.earn = money.convertValue(random); // random is computed @ runtime
    this.earned = money.convertValue(0);

    this.handleClick = function() { 
        this.count ++;
        this.earned = money.convertValue(random * this.count);
    };
});

العمل demo .


بالنسبة لي ، جاء الكشف عندما أدركت أن جميعهم يعملون بالطريقة نفسها: عن طريق تشغيل شيء ما مرة واحدة ، وتخزين القيمة التي يحصلون عليها ، ثم سعال نفس القيمة المخزنة عند الإشارة إليها من خلال حقن التبعية .

قل لدينا:

app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);

الفرق بين الثلاثة هو:

  1. aالقيمة المخزنة تأتي من التشغيل fn.
  2. bالقيمة المخزنة تأتي من newجي fn.
  3. cتأتي القيمة المخزّنة من الحصول أولاً على مثال عن طريق newing fn، ثم تشغيل $getطريقة للمثيل.

مما يعني أن هناك شيئًا مثل كائن ذاكرة التخزين المؤقت داخل AngularJS ، التي يتم تعيين قيمة كل حقنة لها مرة واحدة فقط ، عندما يتم حقنها للمرة الأولى ، وأين:

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()

هذا هو السبب في أننا نستخدم thisفي الخدمات ، وتحديد this.$getمقدمي الخدمات.


كل الإجابات الجيدة بالفعل. وأود أن أضيف بضع نقاط على خدمة و مصنع . جنبا إلى جنب مع الفرق بين الخدمة / المصنع. ويمكن للمرء أيضًا طرح أسئلة مثل:

  1. هل يجب علي استخدام الخدمة أو المصنع؟ ماهو الفرق؟
  2. هل هم متشابهون أم لديهم نفس السلوك؟

لنبدأ بالفرق بين الخدمة والمصنع:

  1. كلاهما Singletons : كلما وجدت Angular هذه كاعتماد أول مرة ، فإنها تخلق نسخة واحدة من الخدمة / المصنع. بمجرد إنشاء المثيل ، يتم استخدام المثيل نفسه إلى الأبد.

  2. يمكن استخدامها لتكوين كائن ذي سلوك : يمكن أن يكون لكل منهما أساليب ومتغيرات الحالة الداخلية وما إلى ذلك. على الرغم من أن الطريقة التي تكتب بها هذا الرمز ستختلف.

خدمات:

الخدمة هي دالة منشئ ، وستقوم Angular بتفعيلها عن طريق الاتصال بـ new yourServiceName(). هذا يعني بضعة أشياء.

  1. ستكون وظائف ومتغيرات الحالة خصائص this.
  2. لست بحاجة إلى إرجاع قيمة. عند إجراء مكالمات Angular new yourServiceName() ، ستتلقى thisالكائن بجميع الخصائص التي تضعها عليه.

مثال على المثال:

angular.service('MyService', function() {
  this.aServiceVariable = "Ved Prakash"
  this.aServiceMethod = function() {
    return //code
  };
});

عندما يقوم Angular بحقن هذه MyServiceالخدمة في وحدة تحكم تعتمد عليها ، ستحصل وحدة التحكم هذه على MyServiceوظائف يمكنها الاتصال بها ، على سبيل المثال MyService.aServiceMethod ().

كن حذرا معthis :

نظرًا لأن الخدمة التي تم إنشاؤها عبارة عن كائن ، يمكن أن تشير الأساليب الموجودة داخلها إلى هذا عندما يتم الاتصال بها:

angular.service('ScoreKeeper', function($http) {
  this.score = 0;

  this.getScore = function() {
    return this.score;
  };

  this.setScore = function(newScore) {
    this.score = newScore;
  };

  this.addOne = function() {
    this.score++;
  };
});

قد تميل إلى الاتصال ScoreKeeper.setScoreفي سلسلة الوعد ، على سبيل المثال ، إذا قمت بتهيئة النتيجة عن طريق الاستيلاء عليها من الخادم: $http.get('/score').then(ScoreKeeper.setScore).المشكلة في هذا هي أنه ScoreKeeper.setScoreسيتم استدعاؤها مع thisالالتزام nullوستحصل على أخطاء. أفضل طريقة ستكون $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper)). سواء اخترت استخدام هذا في أساليب الخدمة الخاصة بك أم لا ، كن حذرا كيف تسميهم.

إرجاع قيمة منService :

نظرًا للطريقة التي تعمل بها أدوات إنشاء جافا سكريبت ، في حالة إرجاع قيمة معقدة (ie, an Object)من إحدى constructorالوظائف ، سيحصل المتصل على هذا الكائن بدلاً من هذا المثيل.

هذا يعني أنه يمكنك أساسا نسخ لصق سبيل المثال مصنع من دون استبدال factoryمع service، وانه سوف يعمل:

angular.service('MyService', function($http) {
  var api = {};

  api.aServiceMethod= function() {
    return $http.get('/users');
  };
  return api;
});

لذلك عندما يقوم Angular بإنشاء خدمتك باستخدام MyService () جديد ، سيحصل على كائن api بدلاً من مثيل MyService.

هذا هو السلوك لأي قيم معقدة (كائنات ، وظائف) ولكن ليس للأنواع البدائية.

المصانع:

المصنع هو وظيفة قديمة واضحة تقوم بإرجاع قيمة. قيمة الإرجاع هي ما يتم حقنه في الأشياء التي تعتمد على المصنع. نمط نموذجي للمصنع في Angular هو إرجاع كائن له وظائف كخصائص ، كما يلي:

angular.factory('MyFactory', function($http) {
  var api = {};

  api.aFactoryMethod= function() {
    return $http.get('/users');
  };

  return api;
});

القيمة المحقونة لتبعية المصنع هي قيمة إرجاع المصنع ، ولا يجب أن تكون كائنًا. يمكن أن يكون وظيفة

الإجابات عن الأسئلة أعلاه والسؤالين المذكورين أعلاه:

بالنسبة للجزء الأكبر ، فقط العصا مع استخدام المصانع في كل شيء. سلوكهم هو أسهل للفهم. لا يوجد أي خيار حول ما إذا كنت تريد إرجاع قيمة أم لا ، وعلاوة على ذلك ، لن يتم إدخال أي أخطاء إذا فعلت الشيء الخطأ.

ما زلت أشير إليهم على أنهم "خدمات" عندما أتحدث عن حقنهم كاعتماديات.

يتشابه سلوك الخدمة / المصنع كثيرًا ، وسيقول بعض الأشخاص أن أحدهما جيد. هذا صحيح إلى حد ما ، ولكن أجد أنه من الأسهل اتباع نصيحة دليل أسلوب جون بابا والتعامل مع المصانع. **


كما أشار العديد من الأشخاص هنا بشكل صحيح ، فإن المصنع والمزود والخدمة وحتى القيمة والثابت هي إصدارات من نفس الشيء. يمكنك تشريح أكثر عمومية providerفي كل منهم. مثل ذلك:

إليك المقالة هذه الصورة من:


ملخص من docs.angularjs.org/guide/providers :

  • هناك خمسة أنواع صفة التي تحدد كيفية إنشاء كائنات: Value ، Factory ، Service ، Provider و Constant .
  • مصنع و الخدمة هي صفات الأكثر شيوعا. والفرق الوحيد بينهما هو أن وصفة الخدمة تعمل بشكل أفضل لكائنات من نوع مخصص ، في حين أن المصنع يمكن أن ينتج مواد ووظائف JavaScript.
  • و مزود صفة نوع الوصفة الأساسية وجميع تلك هي آخر من السكر فقط النحوي على ذلك.
  • الموفر هو نوع الوصفة الأكثر تعقيدًا. لا تحتاج إليها إلا إذا كنت تقوم ببناء جزء من التعليمات البرمجية التي يمكن إعادة استخدامها والتي تحتاج إلى تكوين عالمي.

أفضل الإجابات من SO:

https://.com/a/26924234/165673 (<- GOOD) https://.com/a/27263882/165673
https://.com/a/16566144/165673


وإليك بعض التعليمات البرمجية broilerplate التي اخترتها كقالب لمصنع الكائن في AngularjS. لقد استخدمت سيارة / CarFactory كمثال لتوضيح ذلك. يجعل رمز التنفيذ بسيط في وحدة التحكم.

     <script>
        angular.module('app', [])
            .factory('CarFactory', function() {

                /**
                 * BroilerPlate Object Instance Factory Definition / Example
                 */
                this.Car = function() {

                    // initialize instance properties
                    angular.extend(this, {
                        color           : null,
                        numberOfDoors   : null,
                        hasFancyRadio   : null,
                        hasLeatherSeats : null
                    });

                    // generic setter (with optional default value)
                    this.set = function(key, value, defaultValue, allowUndefined) {

                        // by default,
                        if (typeof allowUndefined === 'undefined') {
                            // we don't allow setter to accept "undefined" as a value
                            allowUndefined = false;
                        }
                        // if we do not allow undefined values, and..
                        if (!allowUndefined) {
                            // if an undefined value was passed in
                            if (value === undefined) {
                                // and a default value was specified
                                if (defaultValue !== undefined) {
                                    // use the specified default value
                                    value = defaultValue;
                                } else {
                                    // otherwise use the class.prototype.defaults value
                                    value = this.defaults[key];
                                } // end if/else
                            } // end if
                        } // end if

                        // update 
                        this[key] = value;

                        // return reference to this object (fluent)
                        return this;

                    }; // end this.set()

                }; // end this.Car class definition

                // instance properties default values
                this.Car.prototype.defaults = {
                    color: 'yellow',
                    numberOfDoors: 2,
                    hasLeatherSeats: null,
                    hasFancyRadio: false
                };

                // instance factory method / constructor
                this.Car.prototype.instance = function(params) {
                    return new 
                        this.constructor()
                                .set('color',           params.color)
                                .set('numberOfDoors',   params.numberOfDoors)
                                .set('hasFancyRadio',   params.hasFancyRadio)
                                .set('hasLeatherSeats', params.hasLeatherSeats)
                    ;
                };

                return new this.Car();

            }) // end Factory Definition
            .controller('testCtrl', function($scope, CarFactory) {

                window.testCtrl = $scope;

                // first car, is red, uses class default for:
                // numberOfDoors, and hasLeatherSeats
                $scope.car1     = CarFactory
                                    .instance({
                                        color: 'red'
                                    })
                                ;

                // second car, is blue, has 3 doors, 
                // uses class default for hasLeatherSeats
                $scope.car2     = CarFactory
                                    .instance({
                                        color: 'blue',
                                        numberOfDoors: 3
                                    })
                                ;
                // third car, has 4 doors, uses class default for 
                // color and hasLeatherSeats
                $scope.car3     = CarFactory
                                    .instance({
                                        numberOfDoors: 4
                                    })
                                ;
                // sets an undefined variable for 'hasFancyRadio',
                // explicitly defines "true" as default when value is undefined
                $scope.hasFancyRadio = undefined;
                $scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);

                // fourth car, purple, 4 doors,
                // uses class default for hasLeatherSeats
                $scope.car4     = CarFactory
                                    .instance({
                                        color: 'purple',
                                        numberOfDoors: 4
                                    });
                // and then explicitly sets hasLeatherSeats to undefined
                $scope.hasLeatherSeats = undefined;
                $scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);

                // in console, type window.testCtrl to see the resulting objects

            });
    </script>

هنا مثال أبسط. أستخدم عددًا قليلاً من مكتبات الجهات الخارجية التي تتوقع ظهور كائن "موضعي" لخط العرض وخط الطول ، ولكن من خلال خصائص كائن مختلفة. لم أكن أرغب في اختراق شفرة البائع ، لذا قمت بتعديل كائنات "الموضع" التي كنت أجولها.

    angular.module('app')
.factory('PositionFactory', function() {

    /**
     * BroilerPlate Object Instance Factory Definition / Example
     */
    this.Position = function() {

        // initialize instance properties 
        // (multiple properties to satisfy multiple external interface contracts)
        angular.extend(this, {
            lat         : null,
            lon         : null,
            latitude    : null,
            longitude   : null,
            coords: {
                latitude: null,
                longitude: null
            }
        });

        this.setLatitude = function(latitude) {
            this.latitude           = latitude;
            this.lat                = latitude;
            this.coords.latitude    = latitude;
            return this;
        };
        this.setLongitude = function(longitude) {
            this.longitude          = longitude;
            this.lon                = longitude;
            this.coords.longitude   = longitude;
            return this;
        };

    }; // end class definition

    // instance factory method / constructor
    this.Position.prototype.instance = function(params) {
        return new 
            this.constructor()
                    .setLatitude(params.latitude)
                    .setLongitude(params.longitude)
        ;
    };

    return new this.Position();

}) // end Factory Definition

.controller('testCtrl', function($scope, PositionFactory) {
    $scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});
    $scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});
}) // end controller

.







angularjs-provider