角度,离子,服务承诺,延迟,异步

时间:2014-12-01 13:48:16

标签: angularjs ionic-framework jquery-deferred ionic

我正在尝试使用运行异步函数的service。 我试图打电话给工厂,然后做一些事情,只有它解决了。 但它不起作用,我收到错误:Uncaught TypeError: Cannot read property 'then' of undefined

我将延迟对象声明为服务函数,并返回其承诺。

你能帮我吗?

app.js:

angular.module('SnowBoard', ['ionic', 'ngCookies', 'ui.unique', 'SnowBoard.controllers', 'SnowBoard.services'])

.run(["isPhoneGap","connectionStatus", 'updateProDB', "$ionicPlatform", '$q', 'sessionService', 'imagesService', function(isPhoneGap, connectionStatus, updateProDB, $ionicPlatform, $q, sessionService, imagesService) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }
  });


  var promise = updateProDB.get();
  promise.then(
          function(data) { 
              imagesService.checkIfImagesExistAllAtOnce(prodata);
          },
          function(error) {

          });
}])

service.js:

.service('updateProDB', ['isPhoneGap', 'connectionStatus', 'isIOS', '$q', 'sessionService', function updateProDBFactory(isPhoneGap, connectionStatus, isIOS, $q, sessionService) {
    this.get = function(){

        var debugOptionUseLocalDB=0;
        var prodata=[];
        var gotANewDB;
        var dbReadyDeferred = $q.defer();

        if (typeof debugOptionUseLocalDB != 'undefined' && debugOptionUseLocalDB) {
            fallbackToLocalDBfile();
            return dbReadyDeferred.promise;
            gotANewDB = 1;
            console.log('on a fini fallbackToLocalDBfile, et dbReadyDeferred.state()='+dbReadyDeferred.state());
        }else{
            if(connectionStatus == 'online'){
                console.log("reaching DB on server (getJsonpFile)...");

                getDBfileXHR(dbUrl()).then(function(){ //if resolved
                        console.log(prodata);
                        return dbReadyDeferred.promise;
                    }, function (){ // if rejected
                        console.log("...basic XHR request failed, falling back to local DB file...and sending mail to dev.");
                        fallbackToLocalDBfile();
                        return dbReadyDeferred.promise;
                        var body = ""; 
                        if ( isPhoneGap ) {
                            body += " Platform : phonegap";
                            body += " device.cordova : "+device.cordova;
                            body += " device.model : "+device.model;
                            body += " device.name : "+device.name;
                            body += " device.platform : "+device.platform;
                            body += " device.uuid : "+device.uuid;
                            body += " device.version : "+device.version;
                        } else {
                            body += "Platform : not phonegap -> web browser"
                            body += "navigator.userAgent : "+navigator.userAgent;
                        }
                        var data={
                                userEmail: "louisromain@yahoo.fr",
                                subject: "BoardLine dev issue: had to fallback to local DB file",
                                destEmail: "louisromain@yahoo.fr",
                                body: body           
                               }
                        sendToServer(data).done(funcSuccess).fail(funcError);
                        function funcSuccess(data /* , textStatus, jqXHR */ ) {
                            console.log("Message to dev successfully sent");
                        }
                        function funcError(data , textStatus, jqXHR  ) {
                            console.log("The message to dev could not be sent...");
                        }
                    });


            }else{ //offline
                console.log('device is offline');
                if(localStorage) {
                    if ( isPhoneGap || !isIOS() ) { //BUG iOS safari doesn't work with this (Cf. Philippe's ipad)
                        if (localStorage.getItem("proDB") === null ) { //if proDB exists in localStorage
                            fallbackToLocalDBfile();
                        } else {
                            //popShortToast("...reading DB in localStorage.");
                            var data = JSON.parse(localStorage["proDB"]); //read current localstorage
                            prodata = storeJsonInProdata(data);
                            sessionService.store('prodata', prodata);
                            dbReadyDeferred.resolve(); //initializeSelectButtons();
                            return dbReadyDeferred.promise;
                        }
                    }
                }else{ //if localStorage not available, read local file
                    prodata = fallbackToLocalDBfile();
                    return dbReadyDeferred.promise;
                }
            }
        }

        function getDBfileXHR(url) {
            var getDBfileXHRdeferred = $q.defer();
            var request = new XMLHttpRequest();
            request.open("GET", url, true); //3rd parameter is sync/async
            request.timeout = 2000;
            //console.log(url);
            request.onreadystatechange = function() {      //Call a function when the state changes.
               if (request.readyState == 4) {
                  if (request.status == 200 || request.status == 0) { 
                     console.log('we get a response from XHR');
                     //popShortToast("...updating DB from server using simple XHR.");
                     var jsonText = request.responseText.replace("callback(", "").replace(");", "");
                     prodata = storeJsonInProdata(JSON.parse(jsonText));
                     sessionService.store('prodata', prodata);
                     // console.log(prodata);
                     gotANewDB = 1; 
                     getDBfileXHRdeferred.resolve();
                     dbReadyDeferred.resolve();
                  } else {
                    console.log('error : request.status = '+request.status);
                    getDBfileXHRdeferred.reject();
                  }
               }
            }
            console.log("Sending XMLHttpRequest...");
            request.send();
            return getDBfileXHRdeferred.promise;
        }
        function dbUrl(){
            return unescape(encodeURIComponent("http://user:pass@boardlineapp.com/app/proDB.jsonp")); //JSONP
        }
        function fallbackToLocalDBfile(){
            getDBfileXHR('proDB.jsonp').then(function(){ //if resolved
                        console.log(prodata);
                        return dbReadyDeferred.promise;
                    });
        }
    }

    function sendToServer(dataToSend) {
        return $.ajax({
            url: 'http://aurel:aurel40@boardlineapp.com/app/mail.php',
            type: "POST",
            dataType: "xml",
            data: dataToSend
        });
    }
    function storeJsonInProdata(data) { //function to store the DB json file into a variable prodata usable in the whole app
        console.log("storing json in prodata");
        //clear prodata first
        var prodata=[];
        //if JSON
        var lines=[];
        for(var i = 0; i <= data.length; i++){
            lines[i]=data[i];
        }
        var fieldnames=lines[0];
        //if tab separated TXT with each model on a separate line
        //      var lines=data.split(/\n/);
        //      var fieldnames=lines[0].split(/\t/);
        var i;
        prodata.push(lines[0]);
        //prodata.push(0);
        for (i = 1; i < lines.length-1; ++i) {
            //if JSON
            var fields=lines[i];
            //if TXT            
            //          var fields=lines[i].split(/\t/);
            //prodata.push(i);          
            var j;
            prodata[i]={};
            prodata[i]['id']=i; //auto id, there is no more 'id' column in the DB file.
            for (j = 0; j < fields.length; ++j) {
                var str=fieldnames[j];
                prodata[i][str]=fields[j];  
            }
        }
        return prodata;
    }

}]);

2 个答案:

答案 0 :(得分:1)

出现至少是一条不返回值的路径,其中的路径是:

   !debugOptionUseLocalBD 
&& connectionStats != 'online' 
&& localStorage 
&& (isPhoneGap || !sIOS()) 
&& localStorage.getItem("proDB") === null

if (connectionStatus == 'online')似乎也没有立即返回任何内容。

我发现代码有点难以理解 - 上述内容可能并不完全准确。

该分支只调用fallbackToLocalDBfile(),似乎没有回复。 (我。)

if (typeof debugOptionUseLocalDB != 'undefined' && debugOptionUseLocalDB) {
  fallbackToLocalDBfile();
  gotANewDB = 1;
  return dbReadyDeferred.promise;
} else {
  if (connectionStatus == 'online') {
    //
    // !!!!!!!!!! HERE !!!!!!!!!!
    //
    getDBfileXHR(dbUrl()).then(function () {
      console.log(prodata);
      return dbReadyDeferred.promise;
    }, function () {
      fallbackToLocalDBfile();

      // The isPhoneGap/etc. and sendToServer() call; elided for clarity
      sendDevMessage();

      return dbReadyDeferred.promise;
    });
  } else {
    if (localStorage) {
      if (isPhoneGap || !isIOS()) { //BUG iOS safari doesn't work with this (Cf. Philippe's ipad)
        if (localStorage.getItem("proDB") === null) {
          //
          // !!!!!!!!!! HERE !!!!!!!!!!
          //
          fallbackToLocalDBfile();
        } else {
          var data = JSON.parse(localStorage["proDB"]);
          prodata = storeJsonInProdata(data);
          sessionService.store('prodata', prodata);
          dbReadyDeferred.resolve();
          return dbReadyDeferred.promise;
        }
      }
    } else {
      prodata = fallbackToLocalDBfile();
      return dbReadyDeferred.promise;
    }
  }
}

没有解释发生错误的情况使得很难进一步提供帮助,但似乎至少有一组条件可以让undefined返回,而可能是我在这里强调的那个。

同样,这或多或少是在黑暗中刺伤。代码很难理解,因为它混合了AngularJS,jQuery(AFAICT,re:$.ajax调用),raw XMLHttpRequests等。存在大量问题,可以对正在发生的事情进行推理很难,至少对我而言。

答案 1 :(得分:0)

路易斯,还有更多的东西,只是确保从所有可能的分支返回一些东西。

你必须确切地知道从每个内部函数返回什么,以便.get()最终将返回prodata的约束,但是派生。

完整的事情可以而且应该在不创建明确的承诺dbReadyDeferredgetDBfileXHRdeferred的情况下完成。它们是不必要的,许多return dbReadyDeferred.promise语句都是错误的。

在角度环境中使用jQuery.ajax()会使生活变得有些尴尬。 “正确”的解决方案是使用$http()代替jQuery.ajax(),但可以通过将jQuery承诺强制转换为$ q来实现(或至少尝试)很多,从而始终保证.get()返回 angualr 承诺。

这个经过大量修改的服务版本未经测试,可能仍需要调试,但应该让您对所需内容有所了解。

.service('updateProDB', ['isPhoneGap', 'connectionStatus', 'isIOS', '$q', 'sessionService', function updateProDBFactory(isPhoneGap, connectionStatus, isIOS, $q, sessionService) {
    this.get = function() {
        var debugOptionUseLocalDB = 0;
        if(typeof debugOptionUseLocalDB != 'undefined' && debugOptionUseLocalDB) {
            return fallbackToLocalDBfile();
        } else {
            if(connectionStatus == 'online') {
                console.log("reaching DB on server (getJsonpFile)...");
                return getDBfileXHR(dbUrl()).then(null, function () {
                    console.log("...basic XHR request failed, falling back to local DB file...and sending mail to dev.");
                    return fallbackToLocalDBfile().then(function(prodata) {
                        var body = [];
                        if (isPhoneGap) {
                            body.push("Platform : phonegap");
                            body.push("device.cordova : " + device.cordova);
                            body.push("device.model : " + device.model);
                            body.push("device.name : " + device.name);
                            body.push("device.platform : " + device.platform);
                            body.push("device.uuid : " + device.uuid);
                            body.push("device.version : " + device.version);
                        } else {
                            body.push("Platform : not phonegap -> web browser");
                            body.push("navigator.userAgent : " + navigator.userAgent);
                        }
                        var data = {
                            userEmail: "louisromain@yahoo.fr",
                            subject: "BoardLine dev issue: had to fallback to local DB file",
                            destEmail: "louisromain@yahoo.fr",
                            body: body.join(' ')
                        };
                        return sendToServer(data).then(function() {
                            return prodata;
                        }, function(textStatus) {
                            console.error("The message to dev could not be sent... :" + textStatus);
                            return textStatus;
                        });
                    });
                });
            } else { //offline
                console.log('device is offline');
                if(localStorage) {
                    if (isPhoneGap || !isIOS()) { //BUG iOS safari doesn't work with this (Cf. Philippe's ipad)
                        if (localStorage.getItem("proDB") === null ) { //if proDB doesn't exist in localStorage
                            return fallbackToLocalDBfile();
                        } else {
                            var data = JSON.parse(localStorage["proDB"]); //read current localstorage
                            var prodata = storeJsonInProdata(data);
                            sessionService.store('prodata', prodata);
                            return $q.when(prodata); //promise of prodata
                        }
                    } else {
                        return fallbackToLocalDBfile();
                    }
                } else { //if localStorage not available, read local file
                    return fallbackToLocalDBfile();
                }
            }
        }
        function getDBfileXHR(url) {
            console.log("Sending XMLHttpRequest...");
            var jqXHR = $.ajax({
                url: url,
                dataType: 'json',
                timeout: 2000
            }).then(function(data) {
                var prodata = storeJsonInProdata(data);
                sessionService.store('prodata', prodata);
                return prodata;
            }, function(jqXHR, textstatus, errorThrown) {
                console.error('getDBfileXHR: url=' + url + ': ' + textstatus);
                return textstatus;
            });
            return $q.when(jqXHR);//coerce jQuery promise to angular
        }
        function dbUrl() {
            return unescape(encodeURIComponent("http://user:pass@boardlineapp.com/app/proDB.jsonp")); //JSONP
        }
        function fallbackToLocalDBfile() {
            return getDBfileXHR('proDB.jsonp');
        }
    }

    function sendToServer(dataToSend) {
        var jqXHR = $.ajax({
            url: 'http://aurel:aurel40@boardlineapp.com/app/mail.php',
            type: "POST",
            dataType: "xml",
            data: dataToSend
        }).then(function(data, textStatus, jqXHR) {
            return data;
        }, function(jqXHR, textStatus, errorThrown) {
            console.error('sendToServer: dataToSend=' + dataToSend + ': ' + textstatus);
            return textStatus;
        });
        return $q.when(jqXHR);//coerce jQuery promise to angular
    }
    function storeJsonInProdata(lines) { //function to store the DB json file into a variable prodata usable in the whole app
        var i, j;
        console.log("storing json in prodata");
        var prodata = [lines[0]];
        for (i = 1; i < lines.length-1; ++i) {
            prodata[i] = { 'id': i }; //auto id, there is no more 'id' column in the DB file.
            for (j = 0; j < lines[i].length; ++j) {
                prodata[i][lines[0][j]] = lines[i][j];
            }
        }
        return prodata;
    }
}]);

我坚持使用与问题中的代码相同的整体结构,但你可以(并且可能应该)通过在每个点fallbackToLocalDBfile(prodata)抛出一个错误来进一步处理并在一个中心处理这些错误广义catch。那会更清洁。

我还试图整理storeJsonInProdata(),这需要进行测试。