2015-06-27 95 views
2

这是我在面试中被问到的一个问题。我知道数组只会返回零,因为这是异步的,但为什么会发生这种情况,以及如何修复它,以便结果数组插入适当的数据?Javascript承诺面试

问题:假设findData是一个函数,它接受查询对象并返回查询结果的承诺。还假设someRandomArrayOfQueries是一个查询对象数组。解释什么会通过下面的代码,为什么被打印:

function runMultipleQueries(queries) { 
var results = []; 
queries.forEach(doQuery); 

return results; 

function doQuery(query) { 
    findData(query) 
    .then(results.push.bind(results)); 
} 
} 

function log(value) { 
console.log(value); 
} 

runMultipleQueries(someRandomArrayOfQueries).forEach(log); 
+4

您确定这是_vanilla JavaScript_? –

+1

你需要阅读关于异步过程的JavaScript。这里重要的是你不知道时间将花费findData。这个承诺不会阻止这个过程。一个承诺只是一个承诺,当他有数据时,他会执行内部的代码,或者内部错误。返回函数将在之前执行,因为javascript过程继续执行代码。 –

+0

@PaulS。代码看起来不错。 –

回答

0

doQuery在将来的某个时候被执行。然而数组立即返回并记录。因此该数组仍然是空的,并且没有记录。 为了解决这个问题,runMultipleQueries也需要返回一个承诺。那可以例如看起来像这样。

function runMultipleQueries(queries) { 
    return Promise.all(queries.map(findData)); 
} 
function log(value) { 
console.log(value); 
} 

runMultipleQueries(someRandomArrayOfQueries).then(function(results) { 
    results.forEach(log); 
}); 

如果你想保持runMultipleQueries类似于你还可以创建这样一个新的承诺原来的,但是这将是不必要的复杂。

function runMultipleQueries(queries) { 
return new Promise(function(resolve, reject) { 
    var results = []; 
    queries.forEach(doQuery); 

    function doQuery(query) { 
    findData(query) 
    .then(function(result) { 
     results.push(result); 
     if(results.length === queries.length) resolve(results); 
    }, reject); 
    } 
}); 
} 

您也可以登录内部doQuery结果,但那么你就必须在其结果记录顺序没有任何保证。此外,这会使你在登录后更难以做任何其他的结果。

function runMultipleQueries(queries) { 
    queries.forEach(doQuery); 

    function log(value) { 
    console.log(value); 
    } 
    function doQuery(query) { 
    findData(query) 
    .then(log); 
    } 
} 

runMultipleQueries(someRandomArrayOfQueries); 
+0

我是否也可以通过在承诺中添加控制台日志来修复它?可以这样做吗? – andy246

+0

你可以这样做 - 我已经添加了另一个例子。但我会建议反对它。 – SpiderPig