当前位置: 首页 > 知识库问答 >
问题:

异步初始化过滤器

楮星鹏
2023-03-14

我在尝试用异步数据初始化过滤器时遇到了麻烦。

过滤器非常简单,它需要将路径转换为名称,但要做到这一点,它需要一个对应数组,我需要从服务器获取该数组。

在返回函数之前,我可以在过滤器定义中做一些事情,但是异步方面阻止了这一点

angular.module('angularApp').
  filter('pathToName', function(Service){
    // Do some things here

    return function(input){
      return input+'!'
    }
  }

使用promise可能是可行的,但我不清楚角度负载是如何过滤的。这篇文章解释了如何通过服务实现这样的魔力,但是对于过滤器也可以这样做吗?

如果有人对如何翻译这些路径有更好的想法,我洗耳恭听。

编辑:

我试着用promise的方法,但是有些不对劲,我看不出是什么:

angular.module('angularApp').filter('pathToName', function($q, Service){

  var deferred = $q.defer();
  var promise = deferred.promise;

  Service.getCorresp().then(function(success){
    deferred.resolve(success.data);
  }, function(error){
    deferred.reject();
  });

  return function(input){
    return promise.then(
      function(corresp){
        if(corresp.hasOwnProperty(input))
          return corresp[input];
        else
          return input;
      }
    )
  };
});

我不太熟悉promise,这是使用promise的正确方式吗?

共有2个答案

于鹏
2023-03-14

让我们从理解为什么原始代码不起作用开始。我将原来的问题简化了一点,使之更清楚:

angular.module('angularApp').filter('pathToName', function(Service) {

    return function(input) {
        return Service.getCorresp().then(function(response) {
            return response;
        });
    });

}

基本上,过滤器调用一个异步函数,该函数返回promise,然后返回其值。angular中的筛选器希望您返回易于打印的值,例如字符串或数字。然而,在这种情况下,尽管我们似乎返回了getCorresp响应,但实际上我们返回了一个新的promise-任何then()catch()函数的返回值都是一个promise。

Angular试图通过强制转换将promise对象转换为字符串,但没有得到任何合理的回报,并显示一个空字符串。

所以我们需要做的是,返回一个临时字符串值并异步更改它,如下所示:

JSFiddle

HTML:

<div ng-app="app" ng-controller="TestCtrl">
    <div>{{'WelcomeTo' | translate}}</div>
    <div>{{'GoodBye' | translate}}</div>
</div>

Javascript:

app.filter("translate", function($timeout, translationService) {

    var isWaiting = false;
    var translations = null;

    function myFilter(input) {

        var translationValue = "Loading...";
        if(translations)
        {
            translationValue = translations[input];
        } else {
            if(isWaiting === false) {
                isWaiting = true;
                translationService.getTranslation(input).then(function(translationData) {
                    console.log("GetTranslation done");
                    translations = translationData;
                    isWaiting = false;
                });
            }
        }

        return translationValue;
    };

    return myFilter;
});

每次Angular尝试执行过滤器时,它都会检查翻译是否已经获取,如果没有,它会返回“加载…”价值我们还使用isWaiting值来防止多次调用该服务。

上述示例适用于Angular 1.2,但是,在Angular 1.3的更改中,有一个性能改进改变了过滤器的行为。以前,每个摘要周期都调用filter函数。但是,由于1.3,它只在值更改时调用过滤器,在我们的上一个示例中,它将不再调用过滤器-“WelcomeTo”将永远不会更改。

幸运的是,修复非常简单,您只需向筛选器添加以下内容:

JSFiddle

myFilter.$stateful = true;

最后,在处理这个问题时,我遇到了另一个问题——我需要使用过滤器来获取可能更改的异步值——具体来说,我需要获取单一语言的翻译,但一旦用户更改了语言,我就需要获取新的语言集。事实证明,这样做有点棘手,尽管概念是一样的。这就是代码:

JSFiddle

var app = angular.module("app",[]);
debugger;

app.controller("TestCtrl", function($scope, translationService) {
    $scope.changeLanguage = function() {
        translationService.currentLanguage = "ru";
    }
});

app.service("translationService", function($timeout) {
    var self = this;

    var translations = {"en": {"WelcomeTo": "Welcome!!", "GoodBye": "BYE"}, 
                        "ru": {"WelcomeTo": "POZHALUSTA!!", "GoodBye": "DOSVIDANYA"} };

    this.currentLanguage = "en";
    this.getTranslation = function(placeholder) {
        return $timeout(function() {
            return translations[self.currentLanguage][placeholder];
        }, 2000);
    }
})

app.filter("translate", function($timeout, translationService) {

    // Sample object: {"en": {"WelcomeTo": {translation: "Welcome!!", processing: false } } }
    var translated = {};
    var isWaiting = false;

    myFilter.$stateful = true;
    function myFilter(input) {

        if(!translated[translationService.currentLanguage]) {
            translated[translationService.currentLanguage] = {}
        }

        var currentLanguageData = translated[translationService.currentLanguage];
        if(!currentLanguageData[input]) {
            currentLanguageData[input] = { translation: "", processing: false };
        }

        var translationData = currentLanguageData[input];
        if(!translationData.translation && translationData.processing === false)
        {
            translationData.processing = true;
            translationService.getTranslation(input).then(function(translation) {
                console.log("GetTranslation done");
                translationData.translation = translation;
                translationData.processing = false;
            });
        }

        var translation = translationData.translation;
        console.log("Translation for language: '" + translationService.currentLanguage + "'. translation = " + translation);
        return translation;
    };

    return myFilter;
});
卫昊东
2023-03-14

以下是一个例子:

app.filter("testf", function($timeout) {
    var data = null, // DATA RECEIVED ASYNCHRONOUSLY AND CACHED HERE
        serviceInvoked = false;

    function realFilter(value) { // REAL FILTER LOGIC
        return ...;
    }

    return function(value) { // FILTER WRAPPER TO COPE WITH ASYNCHRONICITY
        if( data === null ) {
            if( !serviceInvoked ) {
                serviceInvoked = true;
                // CALL THE SERVICE THAT FETCHES THE DATA HERE
                callService.then(function(result) {
                    data = result;
                });
            }
            return "-"; // PLACEHOLDER WHILE LOADING, COULD BE EMPTY
        }
        else return realFilter(value);
    }
});

这个提琴是一个使用超时而不是服务的演示。

编辑:根据sgimeno的评论,必须特别注意不要多次调用该服务。请参阅上述代码和小提琴中的serviceincalled更改。另见1.2角叉式小提琴。1和一个用于更改值和触发摘要循环的按钮:forked fiddle

编辑2:根据Miha Eren的评论,这个解决方案对Angular 1.3不起作用。解决方案几乎是微不足道的,使用$stateful过滤器标志,这里记录在“有状态过滤器”下,以及必要的分叉小提琴。

请注意,这种解决方案会损害性能,因为过滤器被称为每个摘要周期。根据具体情况,性能下降可以忽略不计。

 类似资料:
  • 问题内容: 我在尝试使用异步数据初始化过滤器时遇到麻烦。 过滤器非常简单,它需要将路径转换为名称,但是这样做需要一个对应数组,我需要从服务器中获取该数组。 在返回函数之前,我可以在过滤器定义中执行操作,但是异步方面阻止了该操作 使用诺言可能是可行的,但我对角负载如何过滤没有明确的了解。这篇文章解释了如何通过服务实现这种魔力,但是是否有可能对过滤器做同样的事情? 而且,如果有人对如何翻译这些路径有更

  • SOFABoot 提供了模块并行启动以及 Spring Bean 异步初始化能力,用于加快应用启动速度。本文介绍如何使用 SOFABoot 异步初始化 Spring Bean 能力以提高应用启动速度。 使用场景 在实际使用 Spring/Spring Boot 开发中,一些 Bean 在初始化过程中执行准备操作,如拉取远程配置、初始化数据源等等。在应用启动期间,这些 Bean 会增加 Spring

  • 问题内容: 我想以异步方式初始化模块,并提出一些想法。我需要具有Mongo集合列表和其他数据的DB对象,但是为了简洁起见,其中的文件列表确实有用。 我无法导出函数或类,因为我每次都需要返回相同的对象。 首先 想到的最简单的方法是分配给它,然后填充它: 不好的事情–我真的从外面不知道什么时候准备好列表,也没有检查错误的好方法。 *我想出的 *第二种 方法是继承并通知所有人数据库已准备就绪或发生了错误

  • 当我试图启动我的服务器时,我收到了几个错误。我知道这无法启动数据库,但我可以帮助解决以下问题吗? Pentaho用户控制台 检测到以下错误。 一个或多个系统侦听器失败。这些设置在systemListeners中。xml。 ERROR_0014-尝试执行QuartzSystemListener启动序列时出错org.pentaho.platform.scheduler. 有关检测到的每个错误的更多详细

  • 我有一个AngularJS服务,我想用一些异步数据初始化它。类似这样的事情: 显然,这是行不通的,因为如果在返回之前,有东西试图调用,我将得到一个空指针异常。据我所知,从这里和这里所问的其他一些问题中,我有几个选择,但没有一个看起来很清楚(也许我遗漏了什么): 使用“运行”设置服务 设置应用程序时,请执行以下操作: 那么我的服务将如下所示: 这在某些时候起作用,但如果异步数据的时间恰好比初始化所有

  • 问题内容: 我有一个AngularJS服务,我想使用一些异步数据进行初始化。像这样: 显然,这是行不通的,因为如果在返回之前尝试进行调用,我将得到一个空指针异常。据我从阅读这里和这里提出的其他一些问题中所知道的,我有一些选择,但是它们似乎都不是很干净(也许我错过了一些东西): 安装服务“运行” 设置我的应用程序时,请执行以下操作: 然后我的服务将如下所示: 这有时会起作用,但是如果异步数据恰好比初