我在AngularJS中为Odoo Server编写Service Wrapper,它具有服务器支持的所有方法,并在调用服务时返回延迟承诺。 E.g:
$scope.runRPC = function(){
odooSvc.fields_get('res.users').then(
function(result){
console.log(result); //return a list of users
}
);
}
但是,我需要它是同步的,这就是原因所在。
在Odoo中,它有自己的JSON rpc API,它有几种相互依赖的方法。
例如,
search_read:给你一个关于模型u查询的所有内容的列表 fields_get:给你模型所具有的字段列表 还有更多。
通常在工作的应用程序中,我们需要调用2个或更多API方法来获取我们想要的最终数据。但是,因为在Java中,一切都是异步工作的。代码I图像将是简洁和复杂的。
因此,当我进行每个API调用时,彼此依赖。它看起来像这样:
$scope.setLoginToContactEmail = function(){
odooSvc.search_read('res.users').then(
function(users){
for(var i=0; i < user.length; i++){
user = users[0];
login = user.login
partner_id = user.partner_id
odooSvc.read_model('res.partner', partner_id).then(
function(partner){
if(login === partner.email){
odooSvc.write_model('res.partner', partner_id, {email: login}).then(function(msg){
console.log(msg);
});
}
}
)
}
}
);
}
如果我可以同步运行这些API,或等待数据到达,然后再进行另一次调用。看起来会更简单:
$scope.setLoginToContactEmail = function(){
var users = odooSvc.search_read('res.users');
for(var i=0; i < user.length; i++){
user = users[0];
login = user.login
partner_id = user.partner_id
partner = odooSvc.read_model('res.partner', partner_id);
if (login === partner.email){
odooSvc.write_model('res.partner', partner_id, {email: login});
}
}
}
请指教。感谢。
答案 0 :(得分:1)
异步优于同步。
然而,回调可能变得非常混乱,所以我们有承诺。然而,承诺也会变得混乱,尽管不是那么糟糕。 Async-await是获取同步异步代码的最佳方式,但您必须进行转换。这取决于您想要使用多少工具。
以下是我编写ES5代码的方法(不在.then(
之后开始新行,这会减少一些缩进,我也在for循环中做了一些更改,因为我不确定你的意思):
$scope.setLoginToContactEmail = function () {
odooSvc.search_read('res.users').then(function (users) {
for (var i = 0; i < users.length; i++) {
var user = users[i]
var login = user.login
var partner_id = user.partner_id
odooSvc.read_model('res.partner', partner_id).then(function (partner) {
if (login === partner.email) {
odooSvc.write_model('res.partner', partner_id, { email: login }).then(function (msg) {
console.log(msg)
})
}
})
}
})
}
使用ES6和异步函数的提议可以成为:
$scope.setLoginToContactEmail = async function () {
const users = await odooSvc.search_read('res.users')
for (let user of users) {
const { login, partner_id } = user
const partner = await odooSvc.read_model('res.partner', partner_id)
if (login === partner.email) {
const msg = await odooSvc.write_model('res.partner', partner_id, { email: login })
console.log(msg)
}
}
}
这取决于你想要做多少转化。就个人而言,我会采用ES6的一部分(让/ const,解构,箭头函数,模板字符串,模块,unicode改进,扩展操作符/ rest参数,改进的对象文字,以及可能的类文字),你最常使用的东西/并不难以透露。也许还使用async-await:它不是ES6或ES2016的一部分,但它现在处于第3阶段,因此非常稳定,并且它确实使异步代码更容易阅读。需要注意的是,您必须转换新的ES6 / ES2016 /等。使用Babel或TypeScript的功能,并使用polyfill进行承诺(async-await在内部使用)。
TL; DR:如果你发现自己陷入异步地狱,那么async-await提案可能是最好的解决方案。
答案 1 :(得分:1)
这是a plunker照顾Babel翻译:
<body ng-app="app" ng-controller="AsyncController">
<p>{{ message }}</p>
</body>
angular.module('app', []).controller('AsyncController', ['$timeout', '$scope', async function ($timeout, $scope) {
$scope.message = 'no timeout';
$scope.message = await $timeout(() => 'timeout', 2000);
$scope.$apply();
}]);
async...await
与TypeScript和ES.next中的一样简单。这里应该注意两件事。
第一个是异步控制器内的this
上下文 - 它可能与预期的不同。当使用类并且必要时绑定异步方法时,这可能不是问题。当构造函数是异步的并且从一开始就无法到达this
时,这是非OOP代码的问题。
另一个是async...await
由本机Promises提供支持。这意味着应该调用$scope.$apply()
来触发摘要周期,尽管已经使用了对摘要友好的$timeout
。
答案 2 :(得分:0)
异步方法是我们必须使用的JavaScript的强大功能。原因是,如果任务需要很长时间才能执行,那么我们就不必等待,同时可以执行其他任务。
我们可以看到它在UI上的优势,我们可以在回调中放置长时间的任务,并且可以避免UI变灰。 所以我建议采用异步方法。
但是你决定执行方法的方式并不是Angular方式的更好方法。
Angular已经为你提供了$ q.when(method())。then(successCallback(response));通过它控制只有在完成method()并且可以使用method()响应时才会在successCallback中出现另一个承诺电话。这种方法可以帮助您降低代码的复杂性,因为您试图制作传统上不正确的回调链。
$scope.setLoginToContactEmail = function(){
$q.when(searchRead()).then(function(res) {
modelRead(res);
});
}
function searchRead() {
odooSvc.search_read('res.users').then(
// @TODO
}
);
}
function modelRead(res) {
odooSvc.read_model('res.partner').then(
// @TODO
)
}