angularjs-service - AngularJS:متى تستخدم الخدمة بدلاً من المصنع




angularjs-factory (8)

يرجى تحمل معي هنا. وأنا أعلم أن هناك إجابات أخرى مثل: AngularJS: خدمة مقابل مقابل مقابل مصنع

ومع ذلك ، لا أتمكن من معرفة متى تستخدم الخدمة على المصنع.

من ما يمكنني معرفته بالمصنع يستخدم عادة لإنشاء وظائف "شائعة" يمكن استدعاءها من خلال وحدات تحكم متعددة: إنشاء وظائف وحدة تحكم شائعة

يبدو أن المستندات الزاويّة تفضل المصنع على الخدمة. حتى أنهم يشيرون إلى "الخدمة" عندما يستخدمون مصنعًا أكثر إرباكًا! http://docs.angularjs.org/guide/dev_guide.services.creating_services

متى سيستخدم أحد الخدمة؟

هل هناك شيء ممكن فقط أو أسهل بكثير من خلال الخدمة؟

هل هناك شيء مختلف يجري وراء الكواليس؟ الاختلافات الأداء / الذاكرة؟

وهنا مثال على ذلك. بخلاف طريقة الإعلان ، يبدو أنها متطابقة ولا يمكنني معرفة لماذا أفعل أحدها مقابل الآخر. http://jsfiddle.net/uEpkE/

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

myApp.factory('fooFactory', function() {
    var fooVar;
    var addHi = function(foo){ fooVar = 'Hi '+foo; }

    return {
        setFoobar: function(foo){
            addHi(foo);
        },
        getFoobar:function(){
            return fooVar;
        }
    };
});
myApp.service('fooService', function() {
    var fooVar;
    var addHi = function(foo){ fooVar = 'Hi '+foo;}

    this.setFoobar = function(foo){
        addHi(foo);
    }
    this.getFoobar = function(){
        return fooVar;
    }
});

function MyCtrl($scope, fooService, fooFactory) {
    fooFactory.setFoobar("fooFactory");
    fooService.setFoobar("fooService");
    //foobars = "Hi fooFactory, Hi fooService"
    $scope.foobars = [
        fooFactory.getFoobar(),
        fooService.getFoobar()
    ];
}

Answers

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

مباشرة من مدونته:

app.service('CarService', function() {
   this.dealer="Bad";
    this.numCylinder = 4;
});

app.factory('CarFactory', function() {
    return function(numCylinder) {
      this.dealer="Bad";
        this.numCylinder = numCylinder
    };
});

app.provider('CarProvider', function() {
    this.dealerName = 'Bad';
    this.$get = function() {
        return function(numCylinder) {
            this.numCylinder = numCylinder;
            this.dealer = this.dealerName;
        }
    };
    this.setDealerName = function(str) {
      this.dealerName = str;
    }      
});

هذا يوضح كيف أن CarService سوف ينتج دائما سيارة مع 4 اسطوانات ، لا يمكنك تغييرها للسيارات الفردية. في حين يقوم CarFactory بإرجاع وظيفة حتى تتمكن من عمل new CarFactory في جهاز التحكم الخاص بك ، مرورًا بعدد من الاسطوانات الخاصة بتلك السيارة. لا يمكنك أن تفعل new CarService لأن CarService هو كائن وليس وظيفة.

السبب لا تعمل المصانع على هذا النحو:

app.factory('CarFactory', function(numCylinder) {
      this.dealer="Bad";
      this.numCylinder = numCylinder
});

وتعود تلقائيا وظيفة لك لتكوين ، هو لأنه لا يمكنك القيام بذلك (إضافة أشياء إلى النموذج الأولي / الخ):

app.factory('CarFactory', function() {
    function Car(numCylinder) {
        this.dealer="Bad";
        this.numCylinder = numCylinder
    };
    Car.prototype.breakCylinder = function() {
        this.numCylinder -= 1;
    };
    return Car;
});

انظر كيف هو حرفيا مصنع إنتاج سيارة.

الاستنتاج من مدونته جيد جدًا:

فى الختام،

---------------------------------------------------  
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------  
| Factory | Yes      | Yes          | No          |
---------------------------------------------------  
| Service | Yes      | No           | No          |
---------------------------------------------------  
| Provider| Yes      | Yes          | Yes         |       
---------------------------------------------------  
  1. استخدم الخدمة عندما تحتاج إلى مجرد كائن بسيط مثل Hash ، على سبيل المثال {foo؛ 1، bar: 2} من السهل التعليمة البرمجية ، ولكن لا يمكنك إنشاء مثيل لها.

  2. استخدم المصنع عندما تحتاج إلى إنشاء كائن ، أي عميل جديد () ، تعليق جديد () ، إلخ.

  3. استخدم مزودًا عندما تحتاج إلى تهيئته. أي اختبار رابط ، سؤال وجواب URL ، إنتاج رابط.

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

لا تفعل هذا:

app.factory('CarFactory', function() {
    return {
        numCylinder: 4
    };
});

استخدم الخدمة بدلاً من ذلك:

app.service('CarService', function() {
    this.numCylinder = 4;
});

يمكن استخدام كل من الطريقة التي تريدها : ما إذا كنت تريد إنشاء كائن أو الوصول إلى وظائف من كليهما

يمكنك إنشاء كائن جديد من الخدمة

app.service('carservice', function() {
    this.model = function(){
        this.name = Math.random(22222);
        this.price = 1000;
        this.colour = 'green';
        this.manufacturer = 'bmw';
    }
});

.controller('carcontroller', function ($scope,carservice) { 
    $scope = new carservice.model();
})

ملحوظة :

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

يمكنك إنشاء كائن جديد من المصنع

app.factory('carfactory', function() {
    var model = function(){
        this.name = Math.random(22222);
        this.price = 1000;
        this.colour = 'green';
        this.manufacturer = 'bmw';
    }
    return model;
});

.controller('carcontroller', function ($scope,carfactory) { 
    $scope = new carfactory();
})

ملحوظة :

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

إنشاء خدمة لمجرد الوصول إلى وظائف بسيطة

app.service('carservice', function () {
   this.createCar = function () {
       console.log('createCar');
   };
   this.deleteCar = function () {
       console.log('deleteCar');
   };
});

.controller('MyService', function ($scope,carservice) { 
    carservice.createCar()
})

إنشاء مصنع للتوصل إلى وظائف بسيطة

app.factory('carfactory', function () {
    var obj = {} 
        obj.createCar = function () {
            console.log('createCar');
        };
       obj.deleteCar = function () {
       console.log('deleteCar');
    };
});

.controller('MyService', function ($scope,carfactory) { 
    carfactory.createCar()
})

استنتاج :

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

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

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

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


حتى عندما يقولون أن جميع الخدمات والمصانع فردية ، أنا لا أتفق مع ذلك بنسبة 100٪. أود أن أقول إن المصانع ليست مفردة ، وهذا هو جواب جوابي. أود حقا أن أفكر في الاسم الذي يحدد كل مكون (خدمة / مصنع) ، أعني:

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

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

من الناحية النظرية ، يمكنك التفكير في أن الخدمات تقدم خدمة ، يمكن للمصانع إنشاء نسخ متعددة (كائنات) من الفصل الدراسي


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

وببساطة ، كل واحد من هؤلاء مقدمي الخدمة هو نسخة متخصصة للآخر ، بالترتيب التالي: provider > factory > value / constant / service .

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

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

موفرو AngularJS ، والمصانع ، والخدمات ، وما إلى ذلك هي كل نفس الشيء http://www.simplygoodcode.com/wp-content/uploads/2015/11/angularjs-provider-service-factory-highlight.png

لمزيد من التفاصيل والأمثلة من منشور المدونة ، حيث حصلت على الصورة من: http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


تفسير

لديك أشياء مختلفة هنا:

أول:

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

المرجع: angular.service vs angular.factory

ثانيا:

ضع في اعتبارك جميع مقدمي الخدمة في AngularJS (القيمة ، والثابت ، والخدمات ، والمصانع) فردية!

الثالث:

استخدام واحد أو آخر (خدمة أو مصنع) حول نمط التعليمات البرمجية. ولكن الطريقة الشائعة في AngularJS هي استخدام المصنع .

لماذا ا ؟

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

( المرجع : http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821 ).

استعمال

الخدمة: يمكن أن يكون مفيدا لمشاركة وظائف المرافق المفيدة التي يمكن استدعاؤها بمجرد إلحاق () بمرجع الدالة المحقون. يمكن أيضا أن يتم تشغيل مع injectedArg.call(this) أو ما شابه ذلك.

المصنع: يمكن أن يكون مفيدا في إرجاع وظيفة "الطبقة" التي يمكن أن تكون جديدة بعد ذلك لإنشاء حالات.

لذا ، استخدم مصنعًا عندما يكون لديك منطقًا معقّدًا في خدمتك ولا تريد فضح هذا التعقيد .

في حالات أخرى ، إذا كنت تريد إرجاع مثيل من الخدمة ، فما عليك سوى استخدام الخدمة .

ولكنك سترى بمرور الوقت أنك ستستخدم المصنع في 80٪ من الحالات على ما أعتقد.

لمزيد من التفاصيل: http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/

تحديث :

وظيفة ممتازة هنا: http://iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html

"إذا كنت تريد استدعاء وظيفتك كوظيفة عادية ، فاستخدم المصنّع . إذا كنت تريد أن يتم إنشاء وظيفتك مع المشغل الجديد ، فاستخدم الخدمة. إذا كنت لا تعرف الفرق ، فاستخدم المصنّع".

تحديث :

فريق AngularJS يقوم بعمله ويقدم تفسيرا: http://docs.angularjs.org/guide/providers

ومن هذه الصفحة:

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


خدمات

بناء الجملة : module.service ('serviceName'، function)؛ النتيجة : عند التصريح عن serviceName كوسيطة قابلة للحقن ، سيتم تقديم مرجع الوظيفة الفعلي الذي تم تمريره إلى module.service.

الاستخدام : يمكن أن يكون مفيدا لتبادل وظائف المرافق التي من المفيد أن تستدعي بمجرد الإلحاق () إلى مرجع الدالة المحقون. يمكن أيضا أن يتم تشغيل مع injectedArg.call (هذا) أو ما شابه ذلك.

المصانع

بناء الجملة : module.factory ('factoryName' ، وظيفة) ؛

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

الاستخدام : يمكن أن يكون مفيدا لإرجاع وظيفة "الفئة" التي يمكن بعد ذلك أن تكون جديدة لإنشاء مثيلات.

مقدمي

بناء الجملة : module.provider ('providerName'، function)؛

النتيجة : عند التصريح عن اسم الموفر كوسيطة قابلة للحقن ، سيتم تقديم القيمة التي يتم إرجاعها من خلال استدعاء أسلوب $ get لمرجع الوظيفة الذي تم تمريره إلى module.provider.

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


بواسطة dirty فحص كائن $scope

يحافظ الزاوي على مجموعة بسيطة من المراقبين في كائنات $scope . إذا قمت بفحص أي $scope فسوف تجد أنه يحتوي على array تسمى $$watchers .

كل مراقب هو object يحتوي على أشياء أخرى

  1. تعبير يراقبه المراقب. قد يكون هذا مجرد اسم attribute أو شيء أكثر تعقيدًا.
  2. آخر قيمة معروفة للتعبير. يمكن التحقق من هذا مقابل القيمة المحسوبة الحالية للتعبير. إذا اختلفت القيم ، سيشغل المشاهد الوظيفة ويضع علامة على $scope كمساخ.
  3. وظيفة سيتم تنفيذها إذا كان المراقِب متسخًا.

كيف يتم تحديد مراقبي

هناك العديد من الطرق المختلفة لتعريف مراقب في AngularJS.

  • يمكنك صراحة $watch attribute على $scope .

    $scope.$watch('person.username', validateUnique);
    
  • يمكنك وضع {{}} استيفاء في القالب الخاص بك (سيتم إنشاء مراقب لك على $scope الحالي).

    <p>username: {{person.username}}</p>
    
  • يمكنك أن تطلب توجيهًا مثل ng-model لتحديد المراقب لك.

    <input ng-model="person.username" />
    

تتحقق دورة $digest جميع المراقبين مقابل قيمتها الأخيرة

عندما نتفاعل مع AngularJS من خلال القنوات العادية (ng-model، ng-repeat، etc) سيتم تشغيل دورة الخلاصة بواسطة التوجيه.

تعتبر دورة الموجز عبارة عن اجتياز عمق عام واحد لكل $scope وكل أطفاله . بالنسبة إلى كل object $scope ، فإننا نكرر array $$watchers ونقيم جميع التعبيرات. إذا كانت قيمة التعبير الجديدة مختلفة عن آخر قيمة معروفة ، يتم استدعاء وظيفة المراقب. قد تعيد هذه الوظيفة تجميع جزء من DOM ، أو إعادة حساب قيمة على $scope ، أو تشغيل request AJAX ، أو أي شيء تحتاجه للقيام به.

يتم اجتياز كل نطاق وكل تقييم للساعة يتم تقييمه والتحقق منه مقابل القيمة الأخيرة.

إذا تم تشغيل أحد المراقبين ، فسيكون $scope سيئًا

إذا تم تشغيل أحد المراقبين ، فإن التطبيق يعرف أن شيئًا ما قد تغير ، وأن $scope يتم وضعه على أنه سيئ.

يمكن لوظائف مراقب تغيير سمات أخرى على $scope أو على $scope الأصل. إذا تم تشغيل وظيفة $watcher واحدة ، فلا يمكننا ضمان أن $scope s الآخر الخاص بنا لا يزال نظيفًا ، ولذا فإننا ننفذ دورة الملخص بالكامل مرة أخرى.

ويرجع ذلك إلى أن AngularJS يحتوي على ربط ثنائي الاتجاه ، لذا يمكن تمرير البيانات احتياطيًا لشجرة $scope . قد نغير قيمة على $scope أعلى تم هضمه بالفعل. ربما نغير قيمة على $rootScope .

إذا كان $digest ، فسنقوم بتنفيذ دورة $digest بالكامل مرة أخرى

نتواصل باستمرار من خلال دورة $digest حتى تصبح دورة الهضم نظيفة (جميع تعبيرات $watch لها نفس القيمة التي كانت عليها في الدورة السابقة) ، أو نصل إلى حد الملخص. بشكل افتراضي ، يتم تعيين هذا الحد على 10.

إذا وصلنا إلى حد التلخيص ، فسترفع AngularJS خطأً في وحدة التحكم:

10 $digest() iterations reached. Aborting!

يكون الخلاصة صعبة على الجهاز ولكنها سهلة على المطور

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

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

من السهل الوصول إلى هذا الحد إذا قمت بإعادة ng-repeat على array JSON كبير على سبيل المثال. يمكنك التخفيف من هذا باستخدام ميزات مثل الربط لمرة واحدة لتجميع قالب دون إنشاء مراقبين.

كيف تتجنب إنشاء الكثير من المراقبين

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

إذا كانت لديك بيانات نادرًا ما تتغير ، فيمكنك ربطها مرة واحدة فقط باستخدام بناء الجملة :: مثل:

<p>{{::person.username}}</p>

أو

<p ng-bind="::person.username"></p>

سوف يتم تشغيل الربط فقط عندما يتم تقديم القالب المحتوي على البيانات ويتم تحميل البيانات في $scope .

هذا مهم بشكل خاص عندما يكون لديك ng-repeat مع العديد من العناصر.

<div ng-repeat="person in people track by username">
  {{::person.username}}
</div>






angularjs angularjs-service angularjs-factory