Функциональное программирование раньше было нишевой парадигмой программирования, которая в основном использовалась в академических кругах и научных вычислениях, а также в финансовом мире. Идея функционального программирования — функция как объект. Я новичок в функциональном программировании, и я не использовал функциональное программирование за пределами Linq с C # и в JavaScript с использованием lodash и array.map и т. д. Я хочу реализовать некоторые функции, которые удовлетворяют 3 фундаментальным принципам функционального программирования.
Функция выполняет только одну операцию
Функция не изменяет никакого состояния и, таким образом, предотвращает любые побочные эффекты.
Функция должна работать только с входными данными, не изменяя их.
Функция не должна быть пустой, если это возможно, и должна все время возвращать значение, которое можно использовать в качестве входных данных для последующей операции.
В своей повседневной работе я работаю с SharePoint, и в наши дни большая часть разработки SharePoint происходит на стороне клиента с использованием javascript и других фреймворков. Недавно я написал несколько операций чтения с использованием RestAPI, где я хочу реализовать философию функционального программирования, изложенную выше. Поскольку это операция чтения, пункт № 2 выше будет удовлетворен.
Ниже мой код, и операция проста. Все, что я делаю, это читаю список и возвращаю элементы списка на основе запроса. Я ценю ваш комментарий и предложение, если это можно сделать более совместимым с парадигмой функционального программирования.
Функция находится в AngularJs, но в конечном итоге я преобразую ее в Jquery, чтобы она стала независимой от фреймворка. Как видите, я уже в процессе его изменения.
module My.Common.Services { import entities = My.Entities; export interface IRequestDigest { requestDigest: string; requestDigestExpiration: moment.Moment; } interface ISharePointRestConnection { getRequestDigest(string); } export class SharePointRestConnection implements ISharePointRestConnection { private siteBaseUrl: string; private requestDigest: IRequestDigest; static $inject: string[] = ["$q", "$http", "$interval"]; constructor( private $q: ng.IQService, private $http: ng.IHttpService, private $interval: ng.IIntervalService) { } private parseRequestDigest(data: any, headers: Object): void { this.requestDigest = { requestDigest: data.d.GetContextWebInformation.FormDigestValue, requestDigestExpiration: moment().add(data.d.GetContextWebInformation.FormDigestTimeoutSeconds, "seconds") }; } private parseRequestDigest4mJquery(data: any, headers: Object): void { this.requestDigest = { requestDigest: data.GetContextWebInformation.FormDigestValue, requestDigestExpiration: moment().add(data.GetContextWebInformation.FormDigestTimeoutSeconds, "seconds") }; } public getRequestDigest(siteUrl: string): ng.IPromise<IRequestDigest> { this.siteBaseUrl = siteUrl; var url = siteUrl + "/_api/contextinfo"; var deferred: ng.IDeferred<IRequestDigest> = this.$q.defer<IRequestDigest>(); if (!this.requestDigest) { this.$interval(() => { this.getRequestDigest(this.siteBaseUrl); }, 900000); //900000 ms = 15 minutes, or half of the default expiration } // if the expiration is in the past, or if it doesn't exist yet, then fetch a new one and resolve when complete if ((!this.requestDigest) || (this.requestDigest.requestDigestExpiration < moment())) { var request = { url: url, method: "POST", headers: { "Content-Type": "application/json; odata=verbose", "Accept": "application/json; odata=verbose" } } this.$http(request).then((response: ng.IHttpPromiseCallbackArg<any>) => { this.parseRequestDigest(response.data, response.headers); deferred.resolve(this.requestDigest); }) .catch((response: ng.IHttpPromiseCallbackArg<any>) => { console.log("Failed to get request digest"); deferred.reject(response); }); } else { // if the expiration is in the future deferred.resolve(this.requestDigest); } return deferred.promise; }; public GetStandardSharePointPostHeaders(digest: IRequestDigest): any { return { "Content-Type": "application/json; odata=verbose", "Accept": "application/json; odata=verbose", "X-RequestDigest": digest.requestDigest }; } public GetStandardSharePointMergeHeaders(digest: IRequestDigest): any { return { "Content-Type": "application/json; odata=verbose", "Accept": "application/json; odata=verbose", "X-RequestDigest": digest.requestDigest, "X-HTTP-Method": "MERGE", "IF-MATCH": "*" }; } public GetStandardSharePointDeleteHeaders(digest: IRequestDigest): any { return { "Content-Type": "application/json; odata=verbose", "Accept": "application/json; odata=verbose", "X-RequestDigest": digest.requestDigest, "X-HTTP-Method": "DELETE", "IF-MATCH": "*" }; } public getListItems(url: string, listname: string, query: string): ng.IPromise<any> { var deferred: ng.IDeferred<any> = this.$q.defer<any>(); let requestUrl = url + "/_api/web/lists/getbytitle('" + listname + "')/items" + query; this.getRequestDigest(url).then((digest: IRequestDigest) => { let request: ng.IRequestConfig = { url: requestUrl, method: "GET", headers: { "X-RequestDigest": digest.requestDigest }, }; this.$http(request).then((results: any) => { deferred.resolve(results); }, (error: any) => { console.log("SharePoint Rest Service", "error fetching list items for the list " + listname + " with the query " + query, error); deferred.reject(error); }); }, (error: any) => { console.log("SharePoint Rest Service", "error retrieving SP context", error); deferred.reject(error); }); return deferred.promise; } public getCurrentUser(url: string): ng.IPromise<entities.ISPUser> { var deferred: ng.IDeferred<entities.ISPUser> = this.$q.defer<entities.ISPUser>(); let requestUrl = url + "/_api/web/currentUser"; this.getRequestDigest(url).then((digest: IRequestDigest) => { let request: ng.IRequestConfig = { url: requestUrl, method: "GET", headers: { "X-RequestDigest": digest.requestDigest, "Accept": "application/json; odata=verbose" }, }; this.$http(request).then((results: any) => { let toReturn: My.Entities.SPUser = My.Entities.SPUser.parse(results.data.d); deferred.resolve(My.Entities.SPUser.parse(results.data.d)); }, (error: any) => { console.log("SharePoint Rest Service", "error fetching current user"); deferred.reject(error); }); }, (error: any) => { console.log("SharePoint Rest Service", "error retrieving SP context", error); deferred.reject(error); }); return deferred.promise; } public getListItemsWithCAML(url: string, listname: string, camlQuery: string): ng.IPromise<any> { var deferred: ng.IDeferred<any> = this.$q.defer<any>(); let requestUrl = url + "/_api/web/lists/getbytitle('" + listname + "')/GetItems(query=@v1)?@v1=" + camlQuery; this.getRequestDigest(url).then((digest: IRequestDigest) => { let request: ng.IRequestConfig = { url: requestUrl, method: "POST", headers: { "X-RequestDigest": digest.requestDigest }, }; this.$http(request).then((results: any) => { deferred.resolve(results); }, (error: any) => { console.log("SharePoint Rest Service", "error fetching list items for the list " + listname + " with the query " + camlQuery, error); deferred.reject(error); }); }, (error: any) => { console.log("SharePoint Rest Service", "error retrieving SP context", error); deferred.reject(error); }); return deferred.promise; } public getCurrentUser4mJquery(url: string): any { let deferred = $.Deferred(); let requestUrl = url + "/_api/web/currentUser"; let request: any = { url: requestUrl, method: "GET", headers: { "Accept": "application/json; odata=verbose" }, }; $.get(request).then((results) => { // let toReturn: My.Entities.SPUser = My.SPUser.parse(results.d); deferred.resolve(My.Entities.SPUser.parse(results.d)) }, (error: any) => { console.log("SharePoint Rest Service", "error fetching current user"); deferred.reject(error); }); return deferred.promise(); } public getRequestDigest4mJquery(siteUrl: string): JQueryPromise<IRequestDigest> { this.siteBaseUrl = siteUrl; var url = siteUrl + "/_api/contextinfo"; let deferred = $.Deferred < IRequestDigest>(); if (!this.requestDigest) { setInterval(() => { this.getRequestDigest4mJquery(this.siteBaseUrl); }, 900000); //900000 ms = minutes, or half of the default expiration } // if the expiration is in the past, or if it doesn't exist yet, then fetch a new one and resolve when complete if ((!this.requestDigest) || (this.requestDigest.requestDigestExpiration < moment())) { var request = { url: url, method: "POST", headers: { "Content-Type": "application/json; odata=verbose", "Accept": "application/json; odata=verbose" } } $.get(request).then((response: any) => { console.log(response); this.parseRequestDigest4mJquery(response.d, response.headers); deferred.resolve(this.requestDigest); }) } else { // if the expiration is in the future deferred.resolve(this.requestDigest); } return deferred.promise; }; public getListItemsWithCAML4mJquery(url: string, listname: string, camlQuery: string):any { var deferred = $.Deferred(); let requestUrl = url + "/_api/web/lists/getbytitle('" + listname + "')/GetItems(query=@v1)?@v1=" + camlQuery; $.when(this.getRequestDigest4mJquery(url)).then((digest: IRequestDigest) => { let request: any = { url: requestUrl, method: "POST", headers: { "X-RequestDigest": digest.requestDigest }, }; $.post(request).then((results: any) => { deferred.resolve(results); }, (error: any) => { console.log("SharePoint Rest Service", "error fetching list items for the list " + listname + " with the query " + camlQuery, error); deferred.reject(error); }); }, (error: any) => { console.log("SharePoint Rest Service", "error retrieving SP context", error); deferred.reject(error); }); return deferred.promise; } } angular.module('app'). service("My.Common.Services.sharepointrestconnection", SharePointRestConnection); }
Вот как я его потребляю
this.spRestUtilityService.getCurrentUser(this.BaseWebUrl()).then((results: My.Entities.ISPUser) => { this.spRestUtilityService.getListItemsWithCAML(this.BaseWebUrl(), "ListA", utils.createQuery4UserProfileItem(results)).then((results: any) => { let userProfileItemValue = utils.getSPUserProfileItem(results); this.spRestUtilityService.getListItemsWithCAML(this.BaseWebUrl(), "ListB", this._createQuery4ListB(userProfileItemValue)).then((results: any) => { this.spRestUtilityService.getListItemsWithCAML(this.BaseWebUrl(), "ListB", this._createQuery4ListB4Null(userProfileItemValue)).then((nullResults:any) =>{ deferred.resolve(this._processTableauReportItems(_.uniqBy(_.union(results,nullResults),'Id'))); }); }); }); });
Счастливой пятницы. Ищу ваш комментарий.