حول تكوين الوظيفة في JavaScript

دعونا نتخيل موضوع التكوين الوظيفي ، وكذلك توضيح معنى مشغل / خط أنابيب التكوين.


TL ؛ د
يؤلف وظائف مثل رئيسه:
الصورة
التطبيقات الشائعة compose - عندما يتم استدعائها ، فإنها تنشئ وظائف جديدة وجديدة تعتمد على التكرار ، ما هي العيوب وكيفية التغلب عليها.


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


الدافع


  • الحصول على هوية النقابي:

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


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


 import {memoize} from 'ramda' const memoCompose = memoize(compose) memoCompose(a, b) === memoCompose(a, b) // ,   memoCompose(memoCompose(a, b), c) === memoCompose(a, memoCompose(b, c)) // ,        

  • تبسيط تصحيح التكوين:

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


  • تخلص من العودية ذات الصلة النفقات العامة:

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


الحل


قم بعمل monoid (أو semigroupoid مع دعم لمواصفات الفئة) من حيث fantasy-land:


 import compose, {identity} from 'lazy-compose' import {add} from 'ramda' const a = add(1) const b = add(2) const c = add(3) test('Laws', () => { compose(a, compose(b, c)) === compose(compose(a, b), c) //  compose(a, identity) === a //right identity compose(identity, a) === a //left identity } 

استخدام الحالات


  • مفيد في تحفيظ التراكيب المركبة عند العمل مع المحررين. على سبيل المثال ل redux / mapStateToProps و
    إعادة تحديد.
  • تكوين العدسات.

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


  import {lensProp, memoize} from 'ramda' import compose from 'lazy-compose' const constantLens = memoize(lensProp) const lensA = constantLens('a') const lensB = constantLens('b') const lensC = constantLens('c') const lensAB = compose(lensB, lensA) console.log( compose(lensC, lensAB) === compose(lensC, lensB, lensA) ) 

  • عمليات الاسترجاعات المحفوظة ، مع القدرة على تكوين الوظيفة النهائية لإرسال حدث.

في هذا المثال ، سيتم إرسال رد الاتصال نفسه إلى عناصر القائمة.


 ```jsx import {compose, constant} from './src/lazyCompose' // constant - returns the same memoized function for each argrum // just like React.useCallback import {compose, constant} from 'lazy-compose' const List = ({dispatch, data}) => data.map( id => <Button key={id} onClick={compose(dispatch, makeAction, contsant(id))} /> ) const Button = React.memo( props => <button {...props} /> ) const makeAction = payload => ({ type: 'onClick', payload, }) ``` 

  • تكوين كسول من مكونات React دون إنشاء مكونات ترتيب أعلى. في هذه الحالة ، ستنهي التركيبة البطيئة مجموعة الوظائف ، دون إنشاء عمليات إغلاق إضافية. هذا السؤال يقلق العديد من المطورين الذين يستخدمون مكتبة recompose.


     import {memoize, mergeRight} from 'ramda' import {constant, compose} from './src/lazyCompose' const defaultProps = memoize(mergeRight) const withState = memoize( defaultState => props => { const [state, setState] = React.useState(defaultState) return {...props, state, setState} } ) const Component = ({value, label, ...props)) => <label {...props}>{label} : {value}</label> const withCounter = compose( ({setState, state, ...props}) => ({ ...props value: state, onClick: compose(setState, constant(state + 1)) }), withState(0), ) const Counter = compose( Component, withCounter, defaultProps({label: 'Clicks'}), ) 

  • Monads ومقدمي الطلبات (من حيث fantasy-land) مع تكافؤ صارم من خلال التخزين المؤقت نتيجة التكوين. إذا قمت بالوصول إلى قاموس الكائنات التي تم إنشاؤها مسبقًا داخل مُنشئ الكتابة ، فستحصل على ما يلي:



  type Info = { age?: number } type User = { info?: Info } const mayBeAge = LazyMaybe<Info>.of(identity) .map(getAge) .contramap(getInfo) const age = mayBeAge.ap(data) const maybeAge2 = LazyMaybe<User>.of(compose(getAge, getInfo)) console.log(maybeAge === maybeAge2) //   ,      //           

لقد تم استخدام هذا النهج لفترة طويلة ، لقد قمت بتصميم المستودع هنا .
حزمة NPM: npm i lazy-compose .


من المثير للاهتمام الحصول على ملاحظات حول إغلاق ذاكرة التخزين المؤقت للوظائف التي تم إنشاؤها في وقت التشغيل اعتمادًا على عمليات الإغلاق.


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

Source: https://habr.com/ru/post/ar432196/


All Articles