我正在尝试使用运行异步函数的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;
}
}]);
答案 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
的约束,但是派生。
完整的事情可以而且应该在不创建明确的承诺dbReadyDeferred
和getDBfileXHRdeferred
的情况下完成。它们是不必要的,许多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()
,这需要进行测试。