等待 AngularJS 或 Javascript 中的异步数据(浏览器)
waits for async data in AngularJS or Javascript (Browser)
我正在 AngularJS 中为 Odoo 服务器编写一个服务包装器,它具有服务器支持的所有方法和 return 一个 延迟承诺 当服务被调用时。例如:
$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:给你一个关于你查询的模型的所有内容的列表
fields_get:给你模型拥有的字段列表
还有更多。
通常在一个工作的应用程序中,我们需要调用2个或更多的API方法来获得我们想要的最终数据。但是,因为在 Java 中,一切正常 asynchronously.The 我想象的代码会嵌套和复杂。
因此,当我进行每个 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);
});
}
}
)
}
}
);
}
Vs 如果我可以同步获取那些 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});
}
}
}
请指教。谢谢。
异步方法是我们必须利用的 JavaScript 的力量。原因是,如果任务需要很长时间才能执行,那么我们不必等待,同时可以执行其他任务。
我们可以看到它相对于 UI 的优势,我们可以在回调中放置耗时较长的任务,并且可以避免 UI 变灰。
所以我建议采用aync方法。
但是您决定方法执行的方式并不是 Angular 中更好的方式。
Angular 为您提供了 $q.when(method()).then(successCallback(response));,只有当 method() 执行完成并且method() 响应可用于进行另一个 promise 调用。这种方法将帮助您降低代码的复杂性,因为您试图制作传统上不正确的回调链。
$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
)
}
异步优于同步。
然而,回调会变得非常混乱,所以我们有承诺。然而,承诺也可能变得混乱,尽管没有那么糟糕。 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 的一部分(let/const、解构、箭头函数、模板字符串、模块、unicode 改进、扩展运算符/剩余参数、改进的对象文字,可能还有 class 文字),这些东西你最常使用的/不太难转译。也许还可以使用 async-await:它不是 ES6 或 ES2016 的一部分,但它现在处于第 3 阶段,因此非常稳定,并且它确实使异步代码更容易阅读。需要注意的是,您必须转译新的 ES6/ES2016/etc。使用 Babel or TypeScript 的功能,并为承诺使用 polyfill(async-await 在内部使用)。
TL;DR:如果您发现自己陷入异步地狱,async-await 提议可能是最好的解决方案。
这里 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
。
我正在 AngularJS 中为 Odoo 服务器编写一个服务包装器,它具有服务器支持的所有方法和 return 一个 延迟承诺 当服务被调用时。例如:
$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:给你一个关于你查询的模型的所有内容的列表 fields_get:给你模型拥有的字段列表 还有更多。
通常在一个工作的应用程序中,我们需要调用2个或更多的API方法来获得我们想要的最终数据。但是,因为在 Java 中,一切正常 asynchronously.The 我想象的代码会嵌套和复杂。
因此,当我进行每个 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);
});
}
}
)
}
}
);
}
Vs 如果我可以同步获取那些 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});
}
}
}
请指教。谢谢。
异步方法是我们必须利用的 JavaScript 的力量。原因是,如果任务需要很长时间才能执行,那么我们不必等待,同时可以执行其他任务。
我们可以看到它相对于 UI 的优势,我们可以在回调中放置耗时较长的任务,并且可以避免 UI 变灰。 所以我建议采用aync方法。
但是您决定方法执行的方式并不是 Angular 中更好的方式。
Angular 为您提供了 $q.when(method()).then(successCallback(response));,只有当 method() 执行完成并且method() 响应可用于进行另一个 promise 调用。这种方法将帮助您降低代码的复杂性,因为您试图制作传统上不正确的回调链。
$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
)
}
异步优于同步。
然而,回调会变得非常混乱,所以我们有承诺。然而,承诺也可能变得混乱,尽管没有那么糟糕。 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 的一部分(let/const、解构、箭头函数、模板字符串、模块、unicode 改进、扩展运算符/剩余参数、改进的对象文字,可能还有 class 文字),这些东西你最常使用的/不太难转译。也许还可以使用 async-await:它不是 ES6 或 ES2016 的一部分,但它现在处于第 3 阶段,因此非常稳定,并且它确实使异步代码更容易阅读。需要注意的是,您必须转译新的 ES6/ES2016/etc。使用 Babel or TypeScript 的功能,并为承诺使用 polyfill(async-await 在内部使用)。
TL;DR:如果您发现自己陷入异步地狱,async-await 提议可能是最好的解决方案。
这里 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
。