如何在循环并进行异步承诺调用后获取重新格式化的 json 对象

Posted

技术标签:

【中文标题】如何在循环并进行异步承诺调用后获取重新格式化的 json 对象【英文标题】:How to get a re-formatted json object after looping over it and making asynchronous promise calls 【发布时间】:2017-12-25 13:00:22 【问题描述】:

不确定问题是对还是错。让我简单描述一下问题以便更好地理解。考虑一个多级 json 对象,其键具有随机英文文本字符串作为其值。任务是遍历对象并访问每个节点以创建另一个等效对象,其中包含与以前相同的父对象具有相同键(和级别)的那些英语字符串的翻译文本。使用递归翻译是有效的,但是在一个承诺中它永远不会返回最终的翻译对象。不过没有错误。

对象:

var obj =   
  "MENU": 
    "NODE": "Wait for her",
    "RESPONSE": 
      "ATTR": "We'll meet again",
      "SEMANTICS": "The Dark Knighthood"
    
  ,
  "NODES": 
    "STANDARDLIBRARY": 
      "SERVER": "Never say never again",
      "CATEGORIES":
        "INFOPROTECTION":"Infoprotection",
        "DATAMOTION":"Data In Motion",
        "LOGGING":"Loggin is key to debugging",
        "VERACITY": "Help me understand the best I can",
        "VARIETY": "Silver surfer"
      
    
  
;

代码:

const iterateAttributesAndParseJSON = (o) => 
  return new Promise(
   function (resolve, reject) 
      for(var a in o) 
        if (typeof o[a] == 'object')
          iterateAttributesAndParseJSON(o[a])
        else
          if( o[a] != '' ) 
            translate(o[a], from: 'en', to: 'nl').then( res => 
                //return jsonObj[a]=res.text;
                jsonObj[a]=res.text;
                //console.log(jsonObj);
                resolve(jsonObj);
            ).catch(err => 
              console.error(err)
                reject(err);
            );
          
        
      
     
   );


iterateAttributesAndParseJSON(obj).then(asd =>  console.log(`Resolved:`,  asd) , err => console.log(err))

注意:翻译又是可以的。我使用了这个 npm 模块。 google-translate-api

【问题讨论】:

也许我遗漏了一些东西,但是在调用翻译之后你会立即调用返回。这是否意味着接下来的三行将不会被执行(包括 resolve())? 请立即查看。在原始代码中,return 被注释掉了。我在贴这里的时候打开错了。 此时我唯一能想到的是,在递归调用之后你没有解决它。对我来说,我没有得到任何输出“已解决”,只有函数内的控制台日志。但这里已经很晚了,我得把它收拾好。祝你好运,我明天可能会看看,因为这个问题很有趣。 嗯,不确定但resolve(jsonObj); 不会做这项工作吗? 我找到了另一个 npm 模块,它可能使我能够做到这一点。 :translate-json-object 但是,这个问题对我来说似乎很有趣。我需要查看这个 npm 模块代码库,看看它们是如何管理事物的。我只是无法理解异步性。 【参考方案1】:

我认为您可以使用 promise all 来完成工作,而不是优化代码但可以工作。

    const translate = require('google-translate-api');

    //var jsonObj = ;

    var obj = 
        "MENU": 
            "NODE": "Wait for her",
            "RESPONSE": 
                "ATTR": "We'll meet again",
                "SEMANTICS": "The Dark Knighthood"
            
        ,
        "NODES": 
            "STANDARDLIBRARY": 
                "SERVER": "Never say never again",
                "CATEGORIES": 
                    "INFOPROTECTION": "Infoprotection",
                    "DATAMOTION": "Data In Motion",
                    "LOGGING": "Loggin is key to debugging",
                    "VERACITY": "Help me understand the best I can",
                    "VARIETY": "Silver surfer"
                
            
        
    ;

    var promises = [];

    const iterateAttributesAndParseJSON = (o) => 
        for (var a in o) 
            if (typeof o[a] == 'object') 
                iterateAttributesAndParseJSON(o[a]);
             else 
                if (o[a] != '') 
                    var promise = translate(o[a],  from: 'en', to: 'nl' ).then(res => 
                        var jsonObj = ;
                        jsonObj[a] = res.text;
                        return jsonObj;
                    ).catch(err => 
                        console.error(err)
                        // reject(err);
                    );
                    promises.push(promise);
                
            
        
    

    iterateAttributesAndParseJSON(obj);
    console.log(promises.length);

    Promise.all(promises).then(asd =>  console.log(`Resolved:`, asd) , err => console.log(err))

将打印键和翻译的数组,希望这会有所帮助

【讨论】:

【参考方案2】:

我考虑了一下。我会为此使用非常不同的设计。它更简单,不需要 Promises,只需要一次网络调用

var obj =   
  "MENU": 
    "NODE": "Wait for her",
    "RESPONSE": 
      "ATTR": "We'll meet again",
      "SEMANTICS": "The Dark Knighthood"
    
  ,
  "NODES": 
    "STANDARDLIBRARY": 
      "SERVER": "Never say never again",
      "CATEGORIES":
        "VERACITY": "Help me understand the best I can",
        "VARIETY": "Silver surfer"
      
    
  
;

var vals = [];
shadow = JSON.parse(JSON.stringify( obj ));
function traverse(obj, shadow, vals, cb) 
    if (typeof obj == 'object')
        for (var i in obj)
            if (typeof obj[i] == 'object')
                traverse(obj[i], shadow[i], vals, cb);
            else
                cb(i, obj, shadow, vals);
    else
        return false;


//setup shadow and array of values
traverse(obj, shadow, vals, function(key, o, s, v) 
    v.push(o[key]);
    s[key] = v.length - 1;
);

function callService( cb ) 
    console.log('... calling translation service... please wait..');
    setTimeout( function() 
        //call translation Service HERE use array vals if service accepts arrays
        // or vals.join(DELIM); where DELIM is something you know the service won't touch
        cb(vals.map( function(v) return v + '-translated'));
    , 1000);


callService( function(translatedArr) 
    traverse(obj, shadow, vals, function(key, o, s, v) 
        o[key] = translatedArr[s[key]];
    );
    console.log( obj );
);

如果你喜欢请告诉我。

【讨论】:

以上是关于如何在循环并进行异步承诺调用后获取重新格式化的 json 对象的主要内容,如果未能解决你的问题,请参考以下文章

异步 redis 和承诺

在for循环中同步promises?

获取在 Promise.race 中完成的承诺

Vue.js 模板循环 - 异步 axios 调用

如何在 node.js 中解决可变数量的承诺

Javascript - 异步等待和获取 - 返回值,而不是承诺?