代码之家  ›  专栏  ›  技术社区  ›  Ben Aston

在JavaScript中使用合成

  •  0
  • Ben Aston  · 技术社区  · 6 年前

    我想以函数式的方式发出请求并将其缓存。

    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 功能?

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

    2 回复  |  直到 6 年前
        1
  •  0
  •   Juorder Gonzalez    6 年前

    你几乎快要实现你的目标了,你是在正确的方向上,用构图的概念。也许这段代码可以帮助你实现你的目标。

    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

    所以你可以这样使用它:

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

    您会注意到,在第一次您承诺等待3秒来解析请求时,在第二次调用中,由于缓存,promise将尽快解决promise,如果您尝试使用另一个uri,它将再次等待3秒,并将缓存响应以下次使用它。

        2
  •  0
  •   Jared Smith    6 年前

    您可以使用地图和 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. 您可以使用相同的策略来缓存 结果 获取,与缓存请求分开。