【问题标题】:AngularJS and an async function inside of a serviceAngularJS 和服务中的异步函数
【发布时间】:2013-12-14 11:53:31
【问题描述】:

我在使用异步函数时遇到了这个问题。关键是“执行”不是等待NotificationService.confirm回调的返回。

我的意思是,这会显示一个 PhoneGap 警报,但它不会等待评估用户按下了哪个按钮。因此,您可以在控制台输出中看到 undefined 而不是 false/true/3 值

[编辑]

这是 Maxim Shoutin 提出的代码,但还不行:

NotificationController.js

angular.module('app').controller("NotificationController", function($rootScope) {

    $rootScope.cancel_button = function() {
      var confirm = NotificationService.confirm("Do you want to confirm?", 'Yes!');

      confirm.then(function(result) {
        console.log('Confirm: ' + result);
        if(confirm)   $location.path('/menu');
      }, function(result) {
        console.log('No data returned');
      })
    }

   /* Additional controller code... */
}

NotificationService.js

angular.module('app').factory("NotificationService", function() {

  // Callback function
  var onConfirm = function(button) {
    console.log('Callback function called!!!');
    if(button == 1)       return false;
    else if(button == 2)  return true;
    else if(button == 3)  return 3;
    else                  return false; // dismissed without press button
  };

 return {
     confirm : function(alert_msg, title, buttonsArray) {

        var deferred = $q.defer();

        if(buttonsArray == null) {
             buttonsArray = ['Cancel', 'OK'];
        }

         var data = navigator.notification.confirm(
                        alert_msg,      // message
                        onConfirm,      // callback
                        title,          // title
                        buttonsArray    // buttonsArray
                    );

         deferred.resolve(data);
         return deferred.promise;
      }
  }
}

控制台输出

> Confirm: undefined之前用户按下按钮)

> Callback function called!!!之后用户按下按钮)

【问题讨论】:

标签: javascript angularjs cordova


【解决方案1】:

问题是您在数据实际返回之前解决了承诺。你需要让你的onConfirm 函数访问NotificationService.confirm 正在返回的承诺,并且只在里面调用resolve

【讨论】:

    【解决方案2】:

    $q 的工作原理是让方法引用可能尚不存在的答案,并让它们注册回调以在答案完成时运行。这意味着如果你在与resolve() 相同的代码块中调用defer(),你并没有真正异步使用promise,因为你在它生成后立即解决了它。

    您需要将deferred.resolve(data) 从您的confirm 功能块中移除,并将其放入您的回调函数中。 resolve() 应该总是进入某种回调函数,因为回调函数是您等待异步事件的方式。如果你可以在 getter 中解决一个 Promise,那么它就不是真正的异步了!

    然后,将您的 onConfirm 方法更改为如下所示:

    var onConfirm = function(button) {
      console.log('Callback function called!!!');
      var result= false;
    
      // if(button == 1)    default case
    
      if(button == 2)  { result = true; }
      else if(button == 3)  { result = 3; }
    
      // else               default case
    
     deferred.resolve(result);
    };
    

    现在,我们在通知回调中才解决承诺,这意味着用户已经做出选择,我们会根据用户的决定来解决它。

    最后,您会注意到,如果onConfirm 不在您的服务范围内,它将无法访问它需要解析的deferred 对象。将 onConfirm 移动到您的 confirm 函数中,这样它就可以对该变量进行闭包访问。

    【讨论】:

      【解决方案3】:

      问题是 NotificationService.confirm("Do you want to confirm?", 'Yes!'); 返回 promise (a.e. async)。

      所以应该是这样的:

      var confirm = NotificationService.confirm("Do you want to confirm?", 'Yes!');
      
      // now confirm is a promise
      confirm.then(function (result) {
                  console.log('Confirm: ' + confirm);
      
                  if(confirm)   $location.path('/round/actual');                                    
                          }, function (result) {
                              alert("Error: No data returned");
                          })    
      

      仅用于演示,我们可以使用$timeout 来模拟异步调用:

      app.factory('NotificationService', function($q,$timeout) {
      
        // Callback function
        var onConfirm = function(button) {
      
          var state;
      
          console.log('Callback function called!!!');
          if(button == 1)       state = 'working!';
          else                  state = false; // dismissed without press button
      
          return state;
        };
      
      
        var factory =  {
           confirm : function(alert_msg, title, buttonsArray) {
      
             var deferred = $q.defer();
      
            $timeout(function () {
               var state =  onConfirm(1); // simulate call callback after 3 sec
               deferred.resolve(state);
             }, 3000);
      
             return deferred.promise;
            }
        }
        return factory;
      });
      

      演示Plunker

      在您的情况下,由于navigator.notification.confirm 使用回调,因此您可以尝试从回调中返回 resolve

      【讨论】:

      • 快完成了,但还没有完成。我的意思是,如果我执行 console.log(result) 输出尚未定义,因为在用户按下按钮之前执行不会“暂停”。我用代码更新了询问
      • 嗯,在 Plunker 中,data 是单一方法,但它应该是您通过异步方式获得的数组或模型之类的值
      • 我无法添加 navigator.notification,因为它来自 Cordova.js,在这里不起作用。因为我让那个功能。您可以修改任何简单的测试。感谢您的宝贵时间!
      • 查看我发布的编辑,我在 phonegap 的文档中看到 navigator.notification 仅使用回调
      猜你喜欢
      • 1970-01-01
      • 2014-06-23
      • 2021-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-07
      • 2013-04-23
      • 1970-01-01
      相关资源
      最近更新 更多