AngularJS:Web工作者返回后View未更新

时间:2013-09-04 12:35:02

标签: javascript angularjs promise web-worker

我正在使用库ParallelJS在Web worker中进行加密/解密,但是当promise被解析时,它不会根据模型的更改来更新视图。现在,我知道我必须在$ scope中包含在angularjs范围之外调用的代码。$ apply,但即使这样做也无济于事。

我认为原因是我正在解析一个在angular的范围外调用的回调中的延迟对象。这有点难以解释所以让我展示我的代码:

function _encrypt(options){
... //crypto-js code to do AES encryption
}

function _decrypt(options){
... //crypto-js code to do AES decryption
}

angular.module('CryptoService', []).factory('Cryptor', function($q, $rootScope){
    function Cryptor(){};
    Cryptor.prototype = {
        encrypt: function(string, key) {
            var deferred = $q.defer();
            var ivS = generateIV();
            var p = new Parallel({
                iv: ivS,
                text: string,
                key: key
            }, { evalPath: '/assets/js/eval.min.js' });

            p.require('/assets/js/crypto.min.js');

            p.spawn(_encrypt).then(function(result){
                deferred.resolve(result);
            });

            return deferred.promise;
        },
        decrypt: function(string, key) {
            var deferred = $q.defer();
            var p = new Parallel({
                text: string,
                key: key
            }, { evalPath: '/assets/js/eval.min.js' });

            p.require('/assets/js/crypto.min.js');

            p.spawn(_decrypt).then(function(result){
                deferred.resolve(result);
            });
            return deferred.promise;
        }
    };
    return new Cryptor();
});

angular.module('ContactService', ['CryptoService']).factory('Contact', function($q, $rootScope, Cryptor){
    function Contact(){
        //initialization
    };
    Contact.prototype = {
       query: function(){
           var deferred = $q.defer();
           var options = {};
           _oauth.secureGET(this._endpoint,options).done(function(result){
               Cryptor.decrypt(result.cmc, key).then(function(string){
                   var data = JSON.parse(string);
                   var contacts = [];
                   for (var cidx in data){
                       var objContact = data[cidx];
                       var c = new Contact();
                       for(var pidx in this._properties){
                           var property = this._properties[pidx];
                           c[property] = objContact[property];
                       }
                       contacts.push(c);
                   }
                   //Since _oauth is using a jQuery method to execute the requests we are outside of angularjs' scope, so we need to wrap the promise resolution in 
                   //the $apply method of the rootscope
                   $rootScope.$apply(function(){
                       deferred.resolve(contacts);
                   });
               });

           }.bind(this)).fail(function() {
               $rootScope.$apply(function(){
                   deferred.resolve([]);
               });
           });
           return deferred.promise;
       },
   };
   return new Contact();
});

现在发生了什么:如果我离开代码,则永远不会调用查询方法的回调函数,因为在cryptor服务中,promise在angular的范围之外被调用。如果我将$ rootScope。$ apply wrapper移动到Cryptor服务,则调用Contact服务中的回调,调用控制器内部的回调,但视图不会更新。

有关如何解决此问题的任何提示?

谢谢大家

一个。

2 个答案:

答案 0 :(得分:1)

好的,我觉得很蠢......问题不在于视图没有更新,而是模型为空。由于我错过了bind(this)到Cryptor promise的回调,模型是空的,视图没有显示任何内容。改变这个

Cryptor.decrypt(result.cmc, key).then(function(string){
    var data = JSON.parse(string);
    var contacts = [];
    for (var cidx in data){
        var objContact = data[cidx];
        var c = new Contact();
        for(var pidx in this._properties){
            var property = this._properties[pidx];
            c[property] = objContact[property];
        }
        contacts.push(c);
    }
    //Since _oauth is using a jQuery method to execute the requests we are outside of angularjs' scope, so we need to wrap the promise resolution in 
    //the $apply method of the rootscope
    $rootScope.$apply(function(){
        deferred.resolve(contacts);
    });
});

到此:

Cryptor.decrypt(result.cmc, key).then(function(string){
    ...
}.bind(this));

做了这个伎俩。

答案 1 :(得分:0)

从你的代码:

p.spawn(_encrypt).then(function(result){
    deferred.resolve(result); 
});

Parallel.js的Promise与Angular.js中的承诺不同。所以你需要换行

deferred.resolve(result);

进入Angular.js $ timeout:

$timeout(function(){
    deferred.resolve(result);
}, 0)

以便通知Angular.js