javascript - 没有 RxJS 的异步流控制

标签 javascript promise observable

我正在开发一款移动应用,我希望它是离线优先的。 假设我想显示“公司”页面,所以我请求公司数据。

这就是我所做的,我在本地存储(在我的例子中是 indexedDB)中查找公司数据,同时我调用服务器获取相同的数据(以获取潜在的更新)。在每个回调中,我用获取的数据更新 View 。首先从本地数据更新,然后从远程数据更新。

为了避免竞争条件,我在本地存储回调中检查了一个名为“remoteDataAlreadyFetched”的 bool 值(以防远程数据在存储响应之前到达)

我的问题是:我该如何处理?我的 View Controller 中有 2 个单独的 promise (一个用于本地,一个用于远程)?我应该使用 observable 吗?这看起来有点矫枉过正,因为不会有超过 2 个响应(本地和远程)。我错过了什么吗?

非常感谢您的帮助

编辑:

这就是我使用 RxJS 的方式。不知道在这种情况下使用 Observables 是否是一种不好的做法......

public static getOfflineFirstObservable(localCall, remoteCall): Observable<any> {
  const data$ = new BehaviorSubject(null);
  var hasFetchedRemoteData = false;

  localCall().then(localDatas => {
    if (!hasFetchedRemoteData) data$.next(localDatas);
  });

  remoteCall().then(remoteDatas => {
    data$.next(remoteDatas);
    hasFetchedRemoteData = true;
  });

  return data$.asObservable();
}

最佳答案

如果您处于离线状态,那么尝试获取远程数据将导致拒绝 promise (使用 promise.race)。如果您要做的只是首先从缓存中获取项目(如果它存在),如果它不尝试将其远程获取,您可以执行以下操作:

const cacheBuilder = promises => fetcher => setFn => getFn => url => {
  //using url as key but can be url+JSON.stringify(parameters)+method(GET/POST)
  const key = url;
  //get from cache first if exist
  return getFn(key).catch(()=>{
    if(promises[key]){
      return promises[key];//return active promise
    }
    promises[key]=fetcher(url);
    return promises[key];

  })
  .then(
    result=>{
      if(!promises[key]){//update cache, this will cause requests to server
        fetcher(url).then(result=>setFn(key,result)).catch(ignore=>ignore);
      }
      promises[key]=undefined;
      setFn(key,result);
      return result;
    }
  );
}

const cacheFirst = cacheBuilder(
  {}//store active promises here
)(
  //fetch function (can be $.get or something else)
  //  I am only using url here but you could use (url,params,method,headers) as well
  url=>
    //remove "console.log ||" it's to show that multiple active fetches share promises
    //  asking for fetch("/") multiple times while first time is not resolved
    //  will not cause multiple requests
    console.log("fetching:",url) ||
    fetch(url)
    .then(response=>response.text())
    .then(result=>result.substr(0,10))
)(
  //how to set an item in local storage
  (key,value)=>{
    newStorage = JSON.parse(localStorage.getItem("netCache")||"{}");
    newStorage[key]=value;
    localStorage.setItem("netCache",JSON.stringify(newStorage));
  }
)(
  //how to get an item based on key (can be url or url + JSON.stringify(parameters) or url+params+method...)
  key=>
    Promise.resolve(
      JSON.parse(localStorage.getItem("netCache")||"{}")[key] ||
      Promise.reject("Not in cache")
    )
);

Promise.all([//should not cause multiple requests, should have only one request made
  cacheFirst("/"),
  cacheFirst("/"),
  cacheFirst("/"),
  cacheFirst("/")
]).then(
  ()=>cacheFirst("/")//should come from cache as well, no request made
)

这是一个示例,其中所有实现都在一个函数中,没有传递 fetch、getter 和 setter:

const cacheFirst = (promises => url => {
  //using url as key but can be url+JSON.stringify(parameters)+method(GET/POST)
  const key = url;
  const fetcher = url=>
    fetch(url)
    .then(response=>response.text())
    .then(result=>result.substr(0,10));
  const setFn = (key,value)=>{
    newStorage = JSON.parse(localStorage.getItem("netCache")||"{}");
    newStorage[key]=value;
    localStorage.setItem("netCache",JSON.stringify(newStorage));
  }
  const getFn = key=>
    Promise.resolve(
      JSON.parse(localStorage.getItem("netCache")||"{}")[key] ||
      Promise.reject("Not in cache")
    );
  //get from cache first if exist
  return getFn(key).catch(()=>{
    if(promises[key]){
      return promises[key];//return active promise
    }
    promises[key]=fetcher(url);
    return promises[key];
  })
  .then(
    result=>{
      //update cache if result didn't came from request, this will cause requests to server
      if(!promises[key]){
        fetcher(url)
        .then(result=>setFn(key,result))
        .catch(ignore=>ignore);
      }
      promises[key]=undefined;
      setFn(key,result);
      return result;
    }
  );
})({})//IIFE passing in the promises object to store active promises

关于javascript - 没有 RxJS 的异步流控制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49750330/

相关文章:

java - 可观察到像 Lmax Disruptor 这样的批处理

javascript - Angular 中嵌套订阅的错误

angular - 如何从 Observable 返回数组

javascript - 将javascript变量放入 Play 函数

node.js - promise nodejs + postgresql 中的错误句柄

javascript - 仅处理 promise 错误的正确方法是什么?

javascript - promise 不在 thenable 中提供更新的数组

javascript - Firebase 管理 SDK : How to use listUsers() function as Observable combining recursive calls?

javascript - 如何将javascript(正则表达式)字符串与另一个字符串进行比较/匹配/替换,忽略字符串顺序

javascript - jQuery .css ('right' )不工作