简体   繁体   English

用于缓存的node.js同步请求

[英]node.js synchronous requests for use in caching

I have an issue I need to resolve in my code that has to do with caching API results. 我有一个需要在我的代码中解决的问题,该问题与缓存API结果有关。 I have some async.map like so: 我有一些像这样的async.map:

for(var user of allUsers) {
    var requestList = fill(cache, locations, apiUrl, cacheMap);

    async.map(requestList, function(obj, callback) {
        // ...
    }, function(err, results) {
        // PUT RESULTS INTO A CACHE
    });
}

the function fill simply looks within the cache to see if a location in locations exists, and it not creates a request URL for my API to be run. 功能fill只是看起来在缓存中,看是否在一个位置locations存在,并且它不是为将要运行我的API请求的URL。

I'm realizing however that a cache won't be much use at all with my approach, because my code will dispatch the async.map and immediately start on the next loop iterations fill , meaning the cache won't be synchronized at each iteration of the user. 但是我意识到我的方法根本不会使用缓存,因为我的代码将分派async.map并立即在下一个循环迭代fill ,这意味着缓存不会在每次迭代时同步用户。

How would I go about ensuring that each iteration of the user has an updated version of the cache from the last user? 我将如何确保用户的每次迭代都具有最后一个用户的缓存的更新版本? I need to make very smart use of my limited API calls, so if there are duplicated requests I want to request once, then pull that result from the cache in later requests. 我需要非常巧妙地利用有限的API调用,因此,如果有重复的请求,我想请求一次,然后在以后的请求中从缓存中提取结果。

My only throught right now would be to to a synchronized request instead of an async.map, but I know this goes against the design of node.js. 我目前唯一的要面对的是同步请求而不是async.map,但是我知道这与node.js的设计背道而驰。

for(var user of allUsers) {
    var requestList = fill(cache, locations, apiUrl, cacheMap);

    // sync map instead
    requestList.map(function(obj) {
        var res = sync-request(obj)
        // put request result into cache
    });

    // cont...
}

Use Promises to proxy and cache the API calls. 使用Promises代理和缓存API调用。 Batching API requests and caching the results are extremely simple using Promises. 使用Promises批处理API请求和缓存结果非常简单。 The following little module of code wraps an existing expensiveAPI call in a Promise and caches the resolved result for 60 seconds. 下面的小代码模块将现有的expensiveAPI调用包装在Promise中,并将解析的结果缓存60秒。

// Existing module to call the expensive API
// using the standard callback pattern
var expensiveApi = require("./expensiveApi");
// Using bluebird promise library
// See http://bluebirdjs.com/docs/api-reference.html
var Promise = require("bluebird");

// Promisify the existing callback
expensiveApi = Promise.promisify(expensiveApi);
// Calls to the API will now return a Promise

// A cache for the Promises
var cache = {};

module.exports = function expensiveApiWithPromises(item) {
  // Check whether a cached Promise already exists
  if (cache[item]) {
    // Return it to the caller
    return cache[item];
  }

  // Promise is not in the cache
  cache[item] = expensiveApi(item)
  .then(function(result) {
    // Promise has resolved
    // set the result to expire
    setTimeout(function() {
      delete cache[item];
    }, 60 * 1000); // 60 seconds expiry
    // Return the result
    return result;
  })
  .catch(function(err) {
    // Promise rejected with an error
    // Reset the cache item
    delete cache[item];
    // Propagate the error
    throw err;
  });

  // Return the newly created cached Promise
  return cache[item];
}

You could just iterate over allUsers using async.eachSeries . 你可以只遍历allUsers使用async.eachSeries This will step through in order and keep it asynchronous. 这将按顺序进行并保持异步。

async.eachSeries(allUsers, (user, done) => {
  const requestList = fill(cache, locations, apiUrl, cacheMap);

  async.map(requestList, (obj, callback) => {
    // ..

    callback(null, requestResult);
  }, (err, results) => {
    // PUT RESULTS INTO A CACHE

    done(null, results);
  });
}, cb);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM