Страницы

Поиск по вопросам

воскресенье, 7 июля 2019 г.

Вызвать функцию с динамическим названием

Имеется сервис, который включает в себя несколько функций, возвращающих данные с сервера. Причем для одной модели данных имеется 2 метода: один возвращает данные, которые сохранились локально, второй - делает запрос на сервер и обновляет локальные данные. Существует проверка, которая определяет, возвращать локальные данные или тянуть их из сервера.
Проблема в том, что во всех методах имеется дублирующийся код. Я решил вынести все это дело в отдельный метод. И столкнулся с проблемой динамического вызова функции. Сейчас вы все поймете :)
(function() { exampleService.$inject = ['exmplResource'] function exampleService(exmplResource) { // Тут просто храним данные, ничего такого. const localObj = { passwords: [], statistic: {}, userId: null }; // Здесь наша API сервиса. return { getPasswords, updatePasswordsFromServer, getStatistic, updateStatisticFromServer }; /* Дальше будет 4 метода, они очень похожи. Вопрос, который меня интересует, находится в методе getData */ // Функция, которая должна вернуть все пароли для определенного пользователя function getPasswords(userId) getData('passwords', userId); } // Ходит на сервер за данными и обновляет их локально. function updatePasswordsFromServer(userId) { return exmplResource .getPasswords(userId) .then(onSuccess); function onSuccess(newPasswords) { localObj.passwords.splice(0, localObj.passwords.length); localObj.passwords.push(...newPasswords); localObj.userId = userId; return newPasswords; } } // Такая же фигня, что и с паролями :) function getStatistic(userId) getData('statistic', userId); } // Тоже сгоняли на сервак и локально обновились. function updateStatisticFromServer(userId) { return exmplResource .getStatistic(userId) .then(onSuccess); function onSuccess(newStatistic) { Object.assign(localObj.statistic, newStatistic); localObj.userId = userId; return newStatistic; } } /* !!!!!!!!!!!! Вот это чудо, которое я пытаюсь сотворить :) Смотрим, если данные для этого пользователя есть локально, тогда сразу отдаем ему их. Если нет, вызываем методы, которые у нас есть для обновления локальных данных. */ function getData(field, userId) { function onPromise(resolve) { // Если пользовальтель тот же, то у нас уже есть нужные ему пароли if (localObj.userId === userId) { resolve(localObj[field]); } else { /* вот тут нужно вызвать как-то нужный нам метод на основе "field". window[`update${field}FromServer`](userId) ??? .then(newData => resolve(newData)); */ } } return new Promise(onPromise); } } angular .module('testModule') .service('exampleService', exampleService); })();
Пока писал вопрос, подумал, может не нужно отдельно методы на update выделять? Просто сделать как-то так
function getData(field, userId) { function onPromise(resolve) { // Если пользовальтель тот же, то у нас уже есть нужные ему пароли if (localObj.userId === userId) { resolve(localObj[field]); } else { exmplResource[`update${field}FromServer`][`get${field}`] .then(newData => resolve(newData); } } return new Promise(onPromise); }
Но это читерство. Проблему в первом случае я так и не понял, как решать. Подскажите, пожалуйста, как тут правильнее поступить.
Был бы очень признателен, как дополнение к вопросу, если опытные люди сказали бы, нужно ли вообще вот так изощрятся и динамечески генерить методы. Читабельность пропадает, но зато не дублируется код. Чем здесь лучше пожертвовать? И, может, по коду есть замечания? Хочется научиться писать нормально кодяру, чтобы другие люди могли ее прочитать. Спасибо! :)


Ответ

Как вариант, можно сделать следующим образом.
Поскольку функции updatePasswordsFromServer и updateStatisticFromServer выполняют одно и то же действие, то можно их объединить в одну функцию. Поскольку в них различна только функция, которая вызывается для получения данных, то можно передать эту функцию в параметрах.
Например так:
(function() { exampleService.$inject = ['exmplResource'] function exampleService(exmplResource) { // Тут просто храним данные, ничего такого. const localObj = { passwords: [], statistic: {}, userId: null }; // Создаем параметры для запроса const params = { passwords: { field: 'passwords', method: 'getPasswords' }, statistic: { field: 'statistic', method: 'getStatistic' } }; // Здесь наша API сервиса. return { getPasswords, updatePasswordsFromServer, getStatistic, updateStatisticFromServer }; // Функция, которая должна вернуть все пароли для определенного пользователя function getPasswords(userId) { return getData(params.passwords, userId); } // Такая же фигня, что и с паролями :) function getStatistic(userId) { return getData(params.statistic, userId); } // Ходит на сервер за данными. function update(userId, func) { return exmplResource[func](userId); } /* !!!!!!!!!!!! Вот это чудо, которое я пытаюсь сотворить :) Смотрим, если данные для этого пользователя есть локально, тогда сразу отдаем ему их. Если нет, вызываем методы, которые у нас есть для обновления локальных данных. */ function getData(param, userId) { function onPromise(resolve) { // Если пользовальтель тот же, то у нас уже есть нужные ему пароли if (localObj.userId === userId) { resolve(localObj[param.field]); } else { update(userId, param.method).then(function(result) { localObj[param.field] = result; localObj.userId = userId; resolve(localObj[param.field]); }); } } return new Promise(onPromise); } } angular .module('testModule') .service('exampleService', exampleService); })();

Комментариев нет:

Отправить комментарий