javascript 在 AngularJS 服务中缓存承诺对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18744830/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 13:04:14  来源:igfitidea点击:

Caching a promise object in AngularJS service

javascriptangularjspromiseangular-promise

提问by andrew.fox

I want to implement a dynamic loading of a static resource in AngularJS using Promises. The problem: I have couple components on page which might (or not, depends which are displayed, thus dynamic) need to get a static resource from the server. Once loaded, it can be cached for the whole application life.

我想使用 Promises 在 AngularJS 中实现静态资源的动态加载。问题:我在页面上有几个组件可能(或不,取决于显示的内容,因此是动态的)需要从服务器获取静态资源。加载后,它可以在整个应用程序生命周期中缓存。

I have implemented this mechanism, but I'm new to Angular and Promises, and I want to make sure if this is a right solution \ approach.

我已经实现了这个机制,但我是 Angular 和 Promises 的新手,我想确定这是否是一个正确的解决方案\方法。

var data = null;
var deferredLoadData = null;

function loadDataPromise() {
  if (deferredLoadData !== null)
    return deferredLoadData.promise;

  deferredLoadData = $q.defer();

  $http.get("data.json").then(function (res) {
    data = res.data;
    return deferredLoadData.resolve();
  }, function (res) {
    return deferredLoadData.reject();
  });

  return deferredLoadData.promise;
}

So, only one request is made, and all next calls to loadDataPromise() get back the first made promise. It seems to work for request that in the progress or one that already finished some time ago.

因此,只发出一个请求,所有对 loadDataPromise() 的下一次调用都会返回第一个做出的承诺。它似乎适用于正在进行的请求或前一段时间已经完成的请求。

But is it a good solution to cache Promises?

但它是缓存 Promise 的好方法吗?

回答by Bergi

Is this the right approach?

这是正确的方法吗?

Yes. The use of memoisationon functions that return promises a common technique to avoid the repeated execution of asynchronous (and usually expensive) tasks. The promise makes the caching easy because one does not need to distinguish between ongoing and finished operations, they're both represented as (the same) promise for the result value.

是的。在返回的函数上使用记忆化保证了一种避免重复执行异步(通常是昂贵的)任务的通用技术。承诺使缓存变得容易,因为不需要区分正在进行的和已完成的操作,它们都表示为结果值的(相同)承诺。

Is this the right solution?

这是正确的解决方案吗?

No. That global datavariable and the resolution with undefinedis not how promises are intended to work. Instead, fulfill the promise with the result data! It also makes coding a lot easier:

不。那个全局data变量和解析undefined不是承诺的工作方式。相反,用结果履行承诺data!它还使编码更容易:

var dataPromise = null;

function getData() {
    if (dataPromise == null)
        dataPromise = $http.get("data.json").then(function (res) {
           return res.data;
        });
    return dataPromise;
}

Then, instead of loadDataPromise().then(function() { /* use global */ data })it is simply getData().then(function(data) { … }).

然后,而不是loadDataPromise().then(function() { /* use global */ data })简单地getData().then(function(data) { … }).

To further improve the pattern, you might want to hide dataPromisein a closure scope, and notice that you will need a lookup for different promises when getDatatakes a parameter (like the url).

为了进一步改进该模式,您可能希望隐藏dataPromise在一个闭包作用域中,并注意到当getData接受一个参数(如 url)时,您将需要查找不同的 Promise。

回答by Andzej Maciusovic

For this task I created service called defer-cache-service which removes all this boiler plate code. It writted in Typescript, but you can grab compiled js file. Github source code.

对于这个任务,我创建了一个名为 defer-cache-service 的服务,它删除了所有这些样板代码。它是用 Typescript 编写的,但您可以抓取编译后的 js 文件。Github 源代码

Example:

例子:

function loadCached() {
   return deferCacheService.getDeferred('cacke.key1', function () {
      return $http.get("data.json");
   }); 
} 

and consume

并消耗

loadCached().then(function(data) {
//...
});

One important thing to notice that if let's say two or more parts calling the the same loadDataPromise and at the same time, you must add this check

需要注意的一件重要事情是,如果让我们说两个或更多部分同时调用相同的 loadDataPromise,则必须添加此检查

if (defer && defer.promise.$$state.status === 0) {
   return defer.promise;
}

otherwise you will be doing duplicate calls to backend.

否则你将重复调用后端。

回答by vsync

This design design pattern will cachewhatever is returned the first time it runs , and return the cachedthing every time it's called again.

这种设计设计模式将缓存第一次运行时返回的内容,并在每次再次调用时返回缓存的内容。

const asyncTask = (cache => {
  return function(){
    // when called first time, put the promise in the "cache" variable
    if( !cache ){
        cache = new Promise(function(resolve, reject){
            setTimeout(() => {
                resolve('foo');
            }, 2000);
        });
    }
    return cache;
  }
})();

asyncTask().then(console.log);
asyncTask().then(console.log);

Explanation:

解释:

Simply wrap your function with another self-invoking function which returns a function (your original async function), and the purpose of wrapper function is to provide encapsulating scope for a local variable cache, so that local variable is only accessible within the returned function of the wrapper function and has the exact same value every time asyncTaskis called (other than the very first time)

简单地用另一个自调用函数包装你的函数,它返回一个函数(你原来的异步函数),包装函数的目的是为局部变量提供封装范围cache,这样局部变量只能在返回的函数内访问包装函数并且每次asyncTask调用时都具有完全相同的值(第一次除外)