Использование композиции в JavaScript - PullRequest
0 голосов
/ 10 января 2019

Я хочу сделать запрос и кешировать его в функциональном стиле.

const req = (uri) => 
    (console.log(`requesting: ${uri}`), Promise.resolve({ status: 200 }));

const cache = (fn) => (...args) => 
    fn(...args).then((result) => { console.log('caching:', result) });

const cachedReq = cache(req);

cachedReq('example.com/foo');

Два вопроса:

  1. Этот код идиоматичен?

  2. Как я могу предоставить логику для генерации ключа кеша из результата, сохраняя разделение интересов? Например, я мог бы использовать req для извлечения разных видов ресурсов, которым необходима разная логика для генерации ключа, который будет использоваться в кеше. Как мне передать эту логику генерации ключа для функции cache?

Edit: На самом деле ключ должен быть URI (спасибо @epascarello). Я выбрал плохой пример. Но я хотел бы спросить о более общем случае, когда необходимо предоставлять логику «в сложном виде», сохраняя при этом достаточное разделение интересов.

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Вы можете использовать комбинацию Map и конструктора Request :

// I'll be using ramda for object equality, but any
// deepEquals checker should work.
const R = window.R;

const genRequest = ((cache, eqComparator) => {
  return (url, fetchOpts={}) => {
    const key = {url, fetchOpts};
    const alreadyHave = [...cache.keys].find(x => eqComparator(x, key));
    if (alreadyHave) return cache.get(alreadyHave);
    const req = new Request(url, fetchOpts);
    cache.set(key, req);
    return req;
  };
})(new Map(), R.equals);

const req = genRequest('http://www.google.com');
fetch(req)
  .then(...)
  .catch(...);

Некоторые хорошие свойства выпадают из этого:

  1. Каждый запрос составляется только один раз, но может повторяться fetch ред.
  2. Никаких побочных эффектов, пока вы не получите: создание запроса и его получение являются отдельными.
  3. ... таким образом, проблемы настолько разделены, насколько они могут быть.
  4. Вы можете повторно настроить приложение параметров, чтобы легко поддерживать пользовательские сравнения на равенство, используя тот же кеш.
  5. Вы можете использовать ту же стратегию для кэширования результатов выборки, отдельно от кэширования запросов.
0 голосов
/ 10 января 2019

Вы почти приблизились к достижению своей цели, вы в правильном направлении, с композиционной концепцией. может быть, этот код поможет вам осуществить вашу цель.

Давайте смоделируем вашу функцию req следующим образом:

var req = (uri) => {
    console.log("inside req", uri);
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve({ status: 200 });
        }, 3000);
    });
}

тогда у вас есть версия cacheFunc:

var withCache = (promiseFunc) => {
    const cache = {};
    return (...args) => {
        // suppose first param is uri
        var uri = args[0];
        return new Promise((resolve, reject) => {
            if (cache.hasOwnProperty(uri)) {
                return resolve(cache[uri]);
            }
            promiseFunc(...args).then((data) => {
              cache[uri] = data;
              resolve(data);
            }).catch(reject);
        });
    }
}

Как видите, вам нужно создать и cache объект в первой функции, так что это немного похоже на Curring в JS , поэтому вам нужно обернуть ваш запрос (то есть обещание) обернуто в другое обещание из версии кеша, поэтому перед выполнением функции req необходимо проверить, существует ли какой-либо ответ в кеше с тем же ключом uri, если он есть, поэтому немедленно разрешите обещание, иначе выполните функцию req, как только вы получите ответ, кешируйте ответ и разрешите версию обещания кеша.

Так что вы можете использовать его так:

var cacheReq = withCache(req);
cacheReq('https://anywhere.com').then(console.log.bind(null, 'response')).catch(console.log.bind(null, 'error response'));

вы заметите, что в первый раз, когда вы обещаете подождать до 3 секунд, чтобы выполнить запрос, во втором вызове обещание разрешит обещание как можно скорее из-за кеша, если вы попытаетесь с другим URI, он будет ждать 3 секунды снова и будет кешировать ответ, чтобы использовать его в следующий раз.

Надеюсь, это поможет вам.

...