2015-06-27 2 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. Обещание не блокирует процесс. Обещание - это только обещание, что, когда у него будут данные, он выполнит код внутри, или ошибку внутри catch. Функция возврата будет выполняться ранее, чем тогда, потому что процесс javascript продолжает строку кода. –

+0

@PaulS. Код выглядит нормально. –

ответ

0

doQuery выполняется в какой-то момент в будущем. Однако массив возвращается и регистрируется немедленно. Поэтому массив все еще пуст и ничего не регистрируется. Чтобы исправить это, необходимо вернуть обещание. Это может быть, например, выглядят так.

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

Смежные вопросы