Javascript 链接多个可选异步Ajax请求
我用的是角度1.5.8。我的应用程序中的视图需要相同3个ajax请求的不同组合。有些视图需要所有三个端点的数据,其他视图需要两个端点的数据,甚至一个端点的数据 我正在开发一个管理数据检索的功能,要求应用程序只调用每个端点一次。我希望根据需要调用ajax请求,但仅在需要时调用。目前我已经创建了一个有效的函数,但似乎需要改进 以下函数包含在Javascript 链接多个可选异步Ajax请求,javascript,angularjs,asynchronous,promise,q,Javascript,Angularjs,Asynchronous,Promise,Q,我用的是角度1.5.8。我的应用程序中的视图需要相同3个ajax请求的不同组合。有些视图需要所有三个端点的数据,其他视图需要两个端点的数据,甚至一个端点的数据 我正在开发一个管理数据检索的功能,要求应用程序只调用每个端点一次。我希望根据需要调用ajax请求,但仅在需要时调用。目前我已经创建了一个有效的函数,但似乎需要改进 以下函数包含在$rootScope中。它使用fetchData()。检索数据时,数据存储在全局变量$rootScope.appData中,然后再次调用fetchData()。当
$rootScope
中。它使用fetchData()。检索数据时,数据存储在全局变量$rootScope.appData中,然后再次调用fetchData()
。当检索到所有数据时,将解析延迟承诺,并将数据返回给控制器
$rootScope.appData = {};
$rootScope.loadAppData = function(fetch) {
var deferred = $q.defer();
function getUser() {
$http
.get('https://example.com/api/getUser')
.success(function(result){
$rootScope.appData.currentUser = result;
fetchData();
});
}
function getPricing() {
$http
.get('https://example.com/api/getPricing')
.success(function(result) {
$rootScope.appData.pricing = result;
fetchData();
});
}
function getBilling() {
$http
.get('https://example.com/api/getBilling')
.success(function(result) {
$rootScope.appData.billing = result;
fetchData();
});
}
function fetchData() {
if (fetch.user && !$rootScope.appData.currentUser) {
getUser();
} else if (fetch.pricing && !$rootScope.appData.pricing) {
getPricing();
} else if (fetch.billing && !$rootScope.appData.billing) {
getBilling();
} else {
deferred.resolve($rootScope.appData);
}
}
if ($rootScope.appData.currentUser && $rootScope.appData.pricing &&$rootScope.appData.billing) {
deferred.resolve($rootScope.appData);
} else {
fetchData();
}
return deferred.promise;
};
对象fetch
作为属性提交,该对象显示要调用的ajax请求。调用$rootScope.loadAppData()
的示例,其中仅请求用户和定价数据,如下所示:
$rootScope.loadAppData({user: true, pricing: true}).then(function(data){
//execute view logic.
});
我想知道:
这些功能的链接是否应该以不同的方式进行?fetchData()
函数是否足够,或者这是执行此功能的一种奇怪方式
有没有一种方法可以同时调用所有需要的Ajax请求,但在解决承诺之前要等待所有需要的调用完成
在$rootScope
中存储这样的数据是否不常见李>
我知道这个函数目前没有正确处理错误。这是在使用此代码段之前我将添加的功能,但与我的问题无关 不要使用.success
方法,而是使用。然后使用方法并将数据返回到其成功处理程序:
function getUserPromise() {
var promise = $http
.get('https://example.com/api/getUser')
.then( function successHandler(result) {
//return data for chaining
return result.data;
});
return promise;
}
使用服务而不是$rootScope:
app.service("myService", function($q, $http) {
this.loadAppData = function(fetchOptions) {
//Create first promise
var promise = $q.when({});
//Chain from promise
var p2 = promise.then(function(appData) {
if (!fetchOptions.user) {
return appData;
} else {
var derivedPromise = getUserPromise()
.then(function(user) {
appData.user = user;
//return data for chaining
return appData;
});
return derivedPromise;
);
});
//chain from p2
var p3 = p2.then(function(appData) {
if (!fetchOptions.pricing) {
return appData;
} else {
var derivedPromise = getPricingPromise()
.then(function(pricing) {
appData.pricing = pricing;
//return data for chaining
return appData;
});
return derivedPromise;
);
});
上面的示例创建了一个空对象的承诺。然后,它链接了三个操作。每个操作都会检查是否需要提取。如果需要,将执行提取,并将结果附加到appData
对象;如果不需要获取,则将appData
对象传递给链中的下一个操作
用法:
myService.loadAppData({user: true, pricing: true})
.then(function(appData){
//execute view logic.
}).catch(functon rejectHandler(errorResponse) {
console.log(errorResponse);
throw errorResponse;
});
如果任何提取操作失败,将跳过链中的后续操作,并调用最终的拒绝处理程序
因为调用承诺的.then
方法会返回一个新的派生承诺,所以很容易创建一个承诺链。可以创建任意长度的链,并且由于一个承诺可以用另一个承诺解决(这将进一步推迟其解决),因此可以在链中的任何点暂停/推迟承诺的解决。这使得实现强大的API成为可能 不要使用.success
方法,而是使用。然后使用方法并将数据返回到其成功处理程序:
function getUserPromise() {
var promise = $http
.get('https://example.com/api/getUser')
.then( function successHandler(result) {
//return data for chaining
return result.data;
});
return promise;
}
使用服务而不是$rootScope:
app.service("myService", function($q, $http) {
this.loadAppData = function(fetchOptions) {
//Create first promise
var promise = $q.when({});
//Chain from promise
var p2 = promise.then(function(appData) {
if (!fetchOptions.user) {
return appData;
} else {
var derivedPromise = getUserPromise()
.then(function(user) {
appData.user = user;
//return data for chaining
return appData;
});
return derivedPromise;
);
});
//chain from p2
var p3 = p2.then(function(appData) {
if (!fetchOptions.pricing) {
return appData;
} else {
var derivedPromise = getPricingPromise()
.then(function(pricing) {
appData.pricing = pricing;
//return data for chaining
return appData;
});
return derivedPromise;
);
});
上面的示例创建了一个空对象的承诺。然后,它链接了三个操作。每个操作都会检查是否需要提取。如果需要,将执行提取,并将结果附加到appData
对象;如果不需要获取,则将appData
对象传递给链中的下一个操作
用法:
myService.loadAppData({user: true, pricing: true})
.then(function(appData){
//execute view logic.
}).catch(functon rejectHandler(errorResponse) {
console.log(errorResponse);
throw errorResponse;
});
如果任何提取操作失败,将跳过链中的后续操作,并调用最终的拒绝处理程序
因为调用承诺的.then
方法会返回一个新的派生承诺,所以很容易创建一个承诺链。可以创建任意长度的链,并且由于一个承诺可以用另一个承诺解决(这将进一步推迟其解决),因此可以在链中的任何点暂停/推迟承诺的解决。这使得实现强大的API成为可能 在原始帖子中找到了回答问题2的好方法。使用$q.all()
可以同时执行承诺,在所有承诺完成后立即解决,或者在其中一个承诺失败时立即解决。多亏了@georgeawg,我把这个逻辑添加到了一个服务中。下面是我的重写,将此代码放入服务,并同时运行所有调用:
services.factory('appData', function($http, $q) {
var appData = {};
var coreData = {};
appData.loadAppData = function(fetch) {
var deferred = $q.defer();
var getUser = $q.defer();
var getPricing = $q.defer();
var getBilling = $q.defer();
if (!fetch.user || coreData.currentUser) {
getUser.resolve();
} else {
$http
.get('https://example.com/api/getUser')
.success(function(result){
coreData.currentUser = result;
getUser.resolve();
}).error(function(reason) {
getUser.reject(reason);
});
}
if (!fetch.billing || coreData.billing) {
getBilling.resolve();
} else {
$http
.get('https://example.com/api/getBilling')
.success(function(result) {
coreData.billing = result;
getBilling.resolve();
}).error(function(reason) {
getBilling.reject(reason);
});
}
if (!fetch.pricing || coreData.pricing) {
getPricing.resolve();
} else {
$http
.get('https://example.com/api/getPricing')
.success(function(result) {
coreData.pricing = result;
getPricing.resolve();
}).error(function(reason) {
getPricing.reject(reason);
});
}
$q.all([getPricing.promise, getUser.promise, getBilling.promise]).then(function(result) {
deferred.resolve(coreData);
}, function(reason){
deferred.reject(reason);
});
return deferred.promise;
};
return appData;
});
在原始帖子中找到了回答问题2的好方法。使用$q.all()
可以同时执行承诺,在所有承诺完成后立即解决,或者在其中一个承诺失败时立即解决。多亏了@georgeawg,我把这个逻辑添加到了一个服务中。下面是我的重写,将此代码放入服务,并同时运行所有调用:
services.factory('appData', function($http, $q) {
var appData = {};
var coreData = {};
appData.loadAppData = function(fetch) {
var deferred = $q.defer();
var getUser = $q.defer();
var getPricing = $q.defer();
var getBilling = $q.defer();
if (!fetch.user || coreData.currentUser) {
getUser.resolve();
} else {
$http
.get('https://example.com/api/getUser')
.success(function(result){
coreData.currentUser = result;
getUser.resolve();
}).error(function(reason) {
getUser.reject(reason);
});
}
if (!fetch.billing || coreData.billing) {
getBilling.resolve();
} else {
$http
.get('https://example.com/api/getBilling')
.success(function(result) {
coreData.billing = result;
getBilling.resolve();
}).error(function(reason) {
getBilling.reject(reason);
});
}
if (!fetch.pricing || coreData.pricing) {
getPricing.resolve();
} else {
$http
.get('https://example.com/api/getPricing')
.success(function(result) {
coreData.pricing = result;
getPricing.resolve();
}).error(function(reason) {
getPricing.reject(reason);
});
}
$q.all([getPricing.promise, getUser.promise, getBilling.promise]).then(function(result) {
deferred.resolve(coreData);
}, function(reason){
deferred.reject(reason);
});
return deferred.promise;
};
return appData;
});
谢谢你的回答。在阅读了您的答案/做了更多的研究之后,我很明显,这个逻辑应该包含在服务中。我现在已经在我的项目中做出了改变。您知道一种方法可以并行执行所有必需的调用,而不是按顺序执行,然后在最长的调用完成后返回结果吗?使用$q.all
并行执行XHR。当下一个XHR依赖于上一个XHR的信息时,顺序方法非常有用。例如,在检索用户位置后计算运费。谢谢您的回答。在阅读了您的答案/做了更多的研究之后,我很明显,这个逻辑应该包含在服务中。我现在已经在我的项目中做出了改变。您知道一种方法可以并行执行所有必需的调用,而不是按顺序执行,然后在最长的调用完成后返回结果吗?使用$q.all
并行执行XHR。当下一个XHR依赖于上一个XHR的信息时,顺序方法非常有用。一个例子是calcula