Table des matières
Avant-propos
Une application de favoris
ServiceAgrégation côté serveur" >ServiceAgrégation côté serveur
Agrégation côté client
更进一步
Maison interface Web js tutoriel Une brève discussion sur le didacticiel de programmation fonctionnelle JavaScript (photo)

Une brève discussion sur le didacticiel de programmation fonctionnelle JavaScript (photo)

Mar 13, 2017 pm 05:12 PM

Avant-propos

Lorsque j'étais à Pékin début avril, mon camarade de classe Xu Hao a dit que les articles écrits par des collègues de notre entreprise étaient trop simples et accordaient trop d'attention aux détails. Ensuite, j'ai ramassé les graines de sésame. et j'ai perdu la pastèque, donc je n'ai plus mis à jour le blog (en fait, la cause première est que le projet est trop chargé). La semaine dernière, j'ai participé à l'événement "Martin Fowler Shenzhen Tour" avec plusieurs autres collègues. Mon collègue Tashi et moi avons contribué à un "FullStack Language JavaScript", avec Yang Yun (connu comme le grand diable du Jianghu). ) ) est « Maîtriser la programmation fonctionnelle et contrôler la complexité du système », et celui de Li Xin (connu sous le nom de Xin Ye dans le Jianghu) est « Concurrence : passé et au-delà ».

En répétant avec d'autres collègues, j'ai soudain découvert que nos sujets sont plus ou moins liés. La partie dont j'ai parlé impliquait également des mécanismes de concurrence basés sur les événements et de la programmation fonctionnelle. Si vous y réfléchissez bien, cela devrait être lié aux caractéristiques de JavaScript lui-même :

  1. Basé sur les événements Node.js est très typique en concurrence Un modèle de

  2. La programmation fonctionnelle le rend naturellement compatible avec les rappels, ce qui le rend très approprié pour les mécanismes asynchrones/événementiels

  3. Les fonctionnalités de programmation fonctionnelle le rendent très adapté à l'écriture DSL

Le lendemain de la réunion, j'ai soudain eu envie de réécrire un modèle d'agrégation en utilisant la programmation fonctionnelle dans le code du projet, il s'est avéré que l'idée était vaguement liée à NoSQL, et j'ai découvert en outre que j'avais de nombreuses lacunes.

L'exemple suivant provient d'une scène d'un projet réel, mais le domaine a été changé, mais cela n'affecte pas du tout la lecture et la compréhension du mécanisme qui se cache derrière.

Une application de favoris

Imaginez une application où les utilisateurs peuvent voir une liste des RSS abonnés. Chaque élément de la liste (appelé flux) contient un id, un titre d'article title et un lien vers l'article url.

Le modèle de données ressemble à ceci :

var feeds = [
    {
        'id': 1,
        'url': 'http://abruzzi.github.com/2015/03/list-comprehension-in-python/',
        'title': 'Python中的 list comprehension 以及 generator'
    },
    {
        'id': 2,
        'url': 'http://abruzzi.github.com/2015/03/build-monitor-script-based-on-inotify/',
        'title': '使用inotify/fswatch构建自动监控脚本'
    },
    {
        'id': 3,
        'url': 'http://abruzzi.github.com/2015/02/build-sample-application-by-using-underscore-and-jquery/',
        'title': '使用underscore.js构建前端应用'
    }
];
Copier après la connexion

Le modèle est très simple lorsque cette application simple ne dispose d'aucune information relative à l'utilisateur. Mais très vite, il a fallu étendre l'application de la version autonome à la version Web. Autrement dit, nous avons introduit la notion d'utilisateurs. Chaque utilisateur peut voir une de ces listes. De plus, les utilisateurs peuvent également collecter des flux. Bien entendu, après la collecte, les utilisateurs peuvent également consulter la liste des flux collectés.

feed and user

Étant donné que chaque utilisateur peut collecter plusieurs flux et que chaque flux peut également être collecté par plusieurs utilisateurs, la relation plusieurs-à-plusieurs entre eux est celle indiquée dans la figure ci-dessus. . Vous pouvez également penser à des choses comme :

$ curl http://www.php.cn/:9999/user/1/feeds
Copier après la connexion

pour obtenir tous les 1 utilisateurs feed, etc., mais ce n'est pas important. Le vrai problème est qu'une fois que vous avez obtenu tous les flux, dans l'interface utilisateur ci-dessus, vous devez ajouter un attribut makred à chaque flux. Cet attribut est utilisé pour indiquer si le flux a été collecté. Correspondant à l'interface, il peut s'agir d'une étoile jaune ou d'un cœur rouge.

bookmarkds design

ServiceAgrégation côté serveur

En raison des limitations des bases de données relationnelles, vous devez effectuer une agrégation côté serveur , comme nourrir Enveloppez l'objet pour générer un objet comme FeedWrapper :

public class FeedWrapper {
    private Feed feed;
    private boolean marked;

    public boolean isMarked() {
        return marked;
    }

    public void setMarked(boolean marked) {
        this.marked = marked;
    }

    public FeedWrapper(Feed feed, boolean marked) {
        this.feed = feed;
        this.marked = marked;
    }
}
Copier après la connexion

puis définissez un objet de service comme FeedService :

public ArrayList<FeedWrapper> wrapFeed(List<Feed> markedFeeds, List<Feed> feeds) {
    return newArrayList(transform(feeds, new Function<Feed, FeedWrapper>() {
        @Override
        public FeedWrapper apply(Feed feed) {
            if (markedFeeds.contains(feed)) {
                return new FeedWrapper(feed, true);
            } else {
                return new FeedWrapper(feed, false);
            }
        }
    }));
}
Copier après la connexion

D'accord, cela peut être considéré comme une implémentation passable, mais statiqueJava fortement typé est un peu réticent à le faire, et une fois que de nouveaux changements se produiront (ils se produiront presque certainement), nous devons encore mettre cette partie de la logique Mettez-le en JavaScript et voyez comment cela simplifie ce processus.

Agrégation côté client

Passons au sujet. Dans cet article, nous utiliserons lodash comme bibliothèque de programmation fonctionnelle pour simplifier l'écriture de code. Puisque JavaScript est un langage dynamiquement faiblement typé, nous pouvons ajouter des attributs à un objet à tout moment, de cette façon, une simple opération map peut compléter le code Java correspondant ci-dessus :

_.map(feeds, function(item) {
    return _.extend(item, {marked: isMarked(item.id)});
});
Copier après la connexion

où la fonction. isMarked fera quelque chose comme ceci :

var userMarkedIds = [1, 2];
function isMarked(id) {
    return _.includes(userMarkedIds, id);
}
Copier après la connexion

Autrement dit, vérifiez si les paramètres entrants sont dans une liste userMarkedIds Cette liste peut être obtenue par la requête suivante :

$ curl http://www.php.cn/:9999/user/1/marked-feed-ids
Copier après la connexion
.

Le but d'obtenir uniquement l'identifiant est de réduire la taille des données de transmission réseau. Bien sûr, vous pouvez également demander tous les /marked-feeds puis faire _.pluck(feeds, &#39;id&#39;) localement pour extraire tous les id attributs.

嗯,代码是精简了许多。但是如果仅仅能做到这一步的话,也没有多大的好处嘛。现在需求又有了变化,我们需要在另一个页面上展示当前用户的收藏夹(用以展示用户所有收藏的feed)。作为程序员,我们可不愿意重新写一套界面,如果能复用同一套逻辑当然最好了。

比如对于上面这个列表,我们已经有了对应的模板:

{{#each feeds}}
<li class="list-item">
    <p class="section" data-feed-id="{{this.id}}">
        {{#if this.marked}}
            <span class="marked icon-favorite"></span>
        {{else}}
            <span class="unmarked icon-favorite"></span>
        {{/if}}
        <a href="/feeds/{{this.url}}">
            <p class="detail">
                <h3>{{this.title}}</h3>
            </p>
        </a>
    </p>
</li>
{{/each}}
Copier après la connexion

事实上,这段代码在收藏夹页面上完全可以复用,我们只需要把所有的marked属性都设置为true就行了!简单,很快我们就可以写出对应的代码:

_.map(feeds, function(item) {
    return _.extend(item, {marked: true});
});
Copier après la connexion

漂亮!而且重要的是,它还可以如正常工作!但是作为程序员,你很快就发现了两处代码的相似性:

_.map(feeds, function(item) {
    return _.extend(item, {marked: isMarked(item.id)});
});

_.map(feeds, function(item) {
    return _.extend(item, {marked: true});
});
Copier après la connexion

消除重复是一个有追求的程序员的基本素养,不过要消除这两处貌似有点困难:位于marked:后边的,一个是函数调用,另一个是值!如果要简化,我们不得不做一个匿名函数,然后以回调的方式来简化:

function wrapFeeds(feeds, predicate) {
    return _.map(feeds, function(item) {
        return _.extend(item, {marked: predicate(item.id)});
    });
}
Copier après la connexion

对于feed列表,我们要调用:

wrapFeeds(feeds, isMarked);
Copier après la connexion

而对于收藏夹,则需要传入一个匿名函数:

wrapFeeds(feeds, function(item) {return true});
Copier après la connexion

lodash中,这样的匿名函数可以用_.wrap来简化:

wrapFeeds(feeds, _.wrap(true));
Copier après la connexion

好了,目前来看,简化的还不错,代码缩减了,而且也好读了一些(当然前提是你已经熟悉了函数式编程的读法)。

更进一步

如果仔细审视isMarked函数,会发现它对外部的依赖不是很漂亮(而且这个外部依赖是从网络异步请求来的),也就是说,我们需要在请求到markedIds的地方才能定义isMarked函数,这样就把函数定义绑定到了一个固定的地方,如果该函数的逻辑比较复杂,那么势必会影响代码的可维护性(或者更糟糕的是,多出维护)。

要将这部分代码隔离出去,我们需要将ids作为参数传递出去,并得到一个可以当做谓词(判断一个id是否在列表中的谓词)的函数。

简而言之,我们需要:

var predicate = createFunc(ids);
wrapFeeds(feeds, predicate);
Copier après la connexion

这里的createFunc函数接受一个列表作为参数,并返回了一个谓词函数。而这个谓词函数就是上边说的isMarked。这个神奇的过程被称为柯里化currying,或者偏函数partial。在lodash中,这个很容易实现:

function isMarkedIn(ids) {
    return _.partial(_.includes, ids);
}
Copier après la connexion

这个函数会将ids保存起来,当被调用时,它会被展开为:_.includes(ids, <id>)。只不过这个<id>会在实际迭代的时候才传入:

$(&#39;/marked-feed-ids&#39;).done(function(ids) {
    var wrappedFeeds = wrapFeeds(feeds, isMarkedIn(ids));
    console.log(wrappedFeeds);
});
Copier après la connexion

这样我们的代码就被简化成了:

$(&#39;/marked-feed-ids&#39;).done(function(ids) {
    var wrappedFeeds = wrapFeeds(feeds, isMarkedIn(ids));
    var markedFeeds = wrapFeeds(feeds, _.wrap(true));

    allFeedList.html(template({feeds: wrappedFeeds}));
    markedFeedList.html(template({feeds: markedFeeds}));
});
Copier après la connexion













Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Tutoriel JavaScript simple : Comment obtenir le code d'état HTTP Tutoriel JavaScript simple : Comment obtenir le code d'état HTTP Jan 05, 2024 pm 06:08 PM

Tutoriel JavaScript : Comment obtenir le code d'état HTTP, des exemples de code spécifiques sont requis Préface : Dans le développement Web, l'interaction des données avec le serveur est souvent impliquée. Lors de la communication avec le serveur, nous devons souvent obtenir le code d'état HTTP renvoyé pour déterminer si l'opération a réussi et effectuer le traitement correspondant en fonction de différents codes d'état. Cet article vous apprendra comment utiliser JavaScript pour obtenir des codes d'état HTTP et fournira quelques exemples de codes pratiques. Utilisation de XMLHttpRequest

Comment obtenir facilement le code d'état HTTP en JavaScript Comment obtenir facilement le code d'état HTTP en JavaScript Jan 05, 2024 pm 01:37 PM

Introduction à la méthode d'obtention du code d'état HTTP en JavaScript : Dans le développement front-end, nous devons souvent gérer l'interaction avec l'interface back-end, et le code d'état HTTP en est une partie très importante. Comprendre et obtenir les codes d'état HTTP nous aide à mieux gérer les données renvoyées par l'interface. Cet article explique comment utiliser JavaScript pour obtenir des codes d'état HTTP et fournit des exemples de code spécifiques. 1. Qu'est-ce que le code d'état HTTP ? Le code d'état HTTP signifie que lorsque le navigateur lance une requête au serveur, le service

Quels sont les avantages de l'utilisation des expressions lambda C++ pour la programmation fonctionnelle ? Quels sont les avantages de l'utilisation des expressions lambda C++ pour la programmation fonctionnelle ? Apr 17, 2024 am 10:18 AM

Les expressions lambda C++ apportent des avantages à la programmation fonctionnelle, notamment : Simplicité : les fonctions en ligne anonymes améliorent la lisibilité du code. Réutilisation du code : les expressions Lambda peuvent être transmises ou stockées pour faciliter la réutilisation du code. Encapsulation : fournit un moyen d'encapsuler un morceau de code sans créer de fonction distincte. Cas pratique : filtrer les nombres impairs dans la liste. Calculer la somme des éléments d'une liste. Les expressions Lambda offrent la simplicité, la réutilisabilité et l'encapsulation de la programmation fonctionnelle.

Erreurs et pièges courants de la programmation fonctionnelle Golang Erreurs et pièges courants de la programmation fonctionnelle Golang Apr 30, 2024 pm 12:36 PM

Il existe cinq erreurs et pièges courants dont il faut être conscient lors de l'utilisation de la programmation fonctionnelle dans Go : Évitez toute modification accidentelle des références et assurez-vous que les variables nouvellement créées sont renvoyées. Pour résoudre les problèmes de concurrence, utilisez des mécanismes de synchronisation ou évitez de capturer un état mutable externe. Utilisez la fonctionnalisation partielle avec parcimonie pour améliorer la lisibilité et la maintenabilité du code. Gérez toujours les erreurs dans les fonctions pour garantir la robustesse de votre application. Tenez compte de l'impact sur les performances et optimisez votre code à l'aide de fonctions en ligne, de structures de données aplaties et de lots d'opérations.

Comment optimiser les programmes fonctionnels Golang en utilisant l'évaluation paresseuse ? Comment optimiser les programmes fonctionnels Golang en utilisant l'évaluation paresseuse ? Apr 16, 2024 am 09:33 AM

L'évaluation paresseuse peut être implémentée dans Go en utilisant des structures de données paresseuses : en créant un type de wrapper qui encapsule la valeur réelle et ne l'évalue qu'en cas de besoin. Optimisez le calcul des séquences de Fibonacci dans les programmes fonctionnels, en différant le calcul des valeurs intermédiaires jusqu'à ce que cela soit réellement nécessaire. Cela peut éliminer les frais généraux inutiles et améliorer les performances des programmes fonctionnels.

Expressions Python Lambda : abrégées, concises, puissantes Expressions Python Lambda : abrégées, concises, puissantes Feb 19, 2024 pm 08:10 PM

Les expressions pythonLambda sont un outil puissant et flexible pour créer du code concis, lisible et facile à utiliser. Ils sont parfaits pour créer rapidement des fonctions anonymes qui peuvent être transmises comme arguments à d'autres fonctions ou stockées dans des variables. La syntaxe de base d'une expression Lambda est la suivante : lambdaarguments:expression Par exemple, l'expression Lambda suivante ajoute deux nombres : lambdax,y:x+y Cette expression Lambda peut être transmise à une autre fonction en tant qu'argument comme suit : defsum( x ,y):returnx+yresult=sum(lambdax,y:x+y,1,2)Dans cet exemple

Expressions Python Lambda : découvrir la puissance des fonctions anonymes Expressions Python Lambda : découvrir la puissance des fonctions anonymes Feb 24, 2024 am 09:01 AM

L'expression lambda en python est une autre forme syntaxique de fonction anonyme. C'est une petite fonction anonyme qui peut être définie n'importe où dans le programme. Une expression lambda se compose d'une liste de paramètres et d'une expression, qui peut être n'importe quelle expression Python valide. La syntaxe d'une expression Lambda est la suivante : lambdaargument_list:expression Par exemple, l'expression Lambda suivante renvoie la somme de deux nombres : lambdax,y:x+y. Cette expression Lambda peut être transmise à d'autres fonctions, telles que la carte. () fonction : nombres=[ 1,2,3,4,5]result=map(lambda

Quels sont les avantages et les inconvénients des fonctions Java par rapport aux autres langages de programmation fonctionnels ? Quels sont les avantages et les inconvénients des fonctions Java par rapport aux autres langages de programmation fonctionnels ? Apr 24, 2024 pm 02:51 PM

Les avantages de la programmation fonctionnelle Java incluent la simplicité, la composabilité, la concurrence, la convivialité des tests et les performances. Les inconvénients incluent la courbe d'apprentissage, la difficulté de débogage, la flexibilité limitée et la surcharge de performances. Ses fonctionnalités clés incluent des fonctions pures sans effets secondaires, des pipelines de traitement de données, du code sans état et des API de streaming efficaces.

See all articles