2017-09-15 42 views
0

我有以下功能。它获得一组属性,并将循环遍历它们以将每个属性放入数据库中。但循环将与await声明自动杀:为什么要“等待”在现代Javascript中打破或杀死for循环?

async function importAttributeRecords(attributeValues, languageId, attributes, dataStorage, tx) { 
    for(let attr of attributes) { 
    console.log("Persist", attr) 
    try { 
     await importAttributeRecord(attributeValues, languageId, attr, dataStorage, tx) 
    } 
    catch(err) { 
     console.log(err); 
    } 
    console.log("After persisting"); 
    } 
} 

await的第一次调用将被执行,但之后的第二console.log声明将不会出现。 此外,循环将立即退出。

即使返回承诺,如何在同一个循环中同步执行像importAttributeRecord()这样的函数? 为什么使用“等待”循环危险?

+0

你的意思是跟第二个日志调用一个输出:''在保持后''?抛出异常吗? – k0pernikus

+4

需要更多[mcve]。 – melpomene

+4

循环未被杀死。它被搁置,当你“等待”承诺时会恢复。承诺是异步的。您不能将它们视为同步。 –

回答

1

这可以被描述为“类别错误”。一个for循环基本上是一个同步编程的想法,一个接一个地等待每个事物(通常是)一个数组或其他索引实体内的每个事物。

异步编程,async实现,是一种不同的方法。使用它的最完美的方式只是表达前情景和后情景之间的关系,并让语言考虑时机并可能同时或并行执行。

对于这种情况,这里是你会怎么做:

async function importAttributeRecords(attributeValues, languageId, attributes, dataStorage, tx) { 
    return Promise.all(attributes.map(attr => { 
    console.log("Initiate persist", attr); 
    return importAttributeRecord(attributesValues, languageId, attr, dataStorage, tx).then(result => { 
     console.log("After persisting", attr, result); 
    }).catch(err => { 
     console.log("Error: ", attr, err); 
    })); 
    }); 
} 

你会注意到,现在importAttributeRecords承诺返回一个数组,所以它是合法async。你也会看到这段代码稍微短一点!

+0

1.本例中没有任何内容等待“importAttributeRecord”的承诺。你忘了'Promise.all'吗? 2.问题中的代码没有问题。在循环中使用'await'可能不会被建议,因为它将以串行方式运行,但这并不意味着它不起作用。无论打破OPs代码将会破坏你的代码。 'for'循环基本上是_serial_,但它不是基本上_synchronous_。 – loganfsmyth

+0

@loganfsmyth 1.谁说这个调用者不想使用'Promise.race'?你忘记了这种可能性吗?另外,你是否在说你认为返回'.then'的结果不是惯用的,并且与'async'兼容? 2.你是否在说你认为* serial *与* asynchronous *是惯用的? –

+1

“谁说这个调用者不想使用Promise.race”因为原始问题有一个循环,非常清楚地执行每个项目,等待它们全部。我的观点是'return attributes.map('返回一个承诺数组,没有等待它们中的任何一个完成,原始代码非常明确地只在所有承诺完成后才从函数返回。2.在你的问题中,你说“for循环根本上是一个同步编程的想法”,这是不正确的,我的观点是循环定义了排序行为,代码可以独立于循环使用而同步或异步执行 – loganfsmyth