在JavaScript中使用合成

时间:2019-01-10 13:26:00

标签: javascript functional-programming composition

我想以功能样式发出请求并将其缓存。

passes()

两个问题:

  1. 此代码惯用吗?

  2. 如何在保持关注点分离的同时提供逻辑以从结果生成缓存键?例如,我可能使用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');来检索不同类型的资源,这些资源需要不同的逻辑来生成要在缓存中使用的密钥。我该如何向req函数提供这种密钥生成逻辑?

编辑: 实际上,URI应该是关键(由于@epascarello)。我选择了一个糟糕的例子。但是我想问一个更一般的情况,即在保持适当的关注点分离的同时,需要“向下组合”提供逻辑。

2 个答案:

答案 0 :(得分:0)

您几乎可以接近实现自己的目标,并且您朝着正确的方向前进,并且拥有构图概念。也许这段代码可以帮助您实现目标。

让我们像这样模拟您的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创建到第一个函数中,所以这与Currying in JS有点相似,因此您需要包装请求(这是一个承诺)包装到另一个来自缓存版本的Promise中,因此在执行req函数之前,您需要验证是否有相同的uri键在缓存中存在某些响应(如果存在),因此请立即解决Promise,否则,请执行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秒钟,然后将缓存响应以便下次使用。

希望它可以为您提供帮助。

答案 1 :(得分:0)

您可以结合使用地图和Request constructor

// 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. 您可以使用相同的策略来缓存获取的结果,而不是缓存请求。