myList = [[1]*4] * 3
создает один объект списка [1,1,1,1]
в памяти и копирует его ссылку 3 раза. Это эквивалентно obj = [1,1,1,1]; myList = [obj]*3
. Любая модификация obj
будет отражена в трех местах, где obj
упоминается в списке. Правильным утверждением будет:
myList = [[1]*4 for _ in range(3)]
или
myList = [[1 for __ in range(4)] for _ in range(3)]
. Важно отметить, что *
оператор в основном используется для создания список литералов. Поскольку 1
является литералом, значит, obj =[1]*4
создаст [1,1,1,1]
, где каждый 1
будет атомарным, а не ссылкой 1
, повторяемым 4 раза. Это означает, что если мы obj[2]=42
, то obj
станет [1,1,42,1]
не [42,42,42,42]
, как могут предположить некоторые.
Здесь две вещи: - Ваша getRecord
функция не возвращает Promise
, поэтому ожидание ничего не ждет - forEach
не может работать с асинхронными функциями, так как реализация не ожидает.
Для первой проблемы вы можете решить ее, выполнив:
async function getRecord(cell_date) {
return $.ajax({
url: 'rec/getRecord/'+cell_date,
type: 'get',
dataType: 'json',
})
.then(response => response.data);
}
Для второй проблемы вы можете сделать это, выполнив цикл следующим образом:
async function testAsyncAwaitFunction() {
let layerNames = await getCellLayers();
for (layerName of layerNames) {
cell_date = layerName.substring(3)+"_"+window['currentImage'].substring(17,25);
console.log(cell_date+":");
let cellRecord = await getRecord(cell_date);
console.log("Matches: "+cellRecord.length);
console.log("testAsyncAwaitFunction response: "+JSON.stringify(cellRecord));
}
}
[1110 ] Но при этом все запускается один за другим. Вы могли бы сделать еще лучше, отправив запросы, а затем дождавшись завершения всех из них, используя Promise.all
следующим образом:
const promises = []
for (layerName of layerNames) {
cell_date = layerName.substring(3)+"_"+window['currentImage'].substring(17,25);
console.log(cell_date+":");
promises.push(getRecord(cell_date));
}
const records = await Promise.all(promises)
Что нужно помнить об асинхронности, так это о том, что любая функция с добавленной асинхронностью должна возвращать Обещание. getRecord должен вернуть то, что у вас есть. Кроме того, в то время как ваша внешняя функция testAsyncAwaitFunction является асинхронной, а ваш обратный вызов forEach - асинхронным, у вас нет ничего ожидающего разрешения ВСЕХ обещаний вашего forEach.
Вы хотите этот шаблон:
async function testAsyncAwaitFunction() {
let layerNames = await getCellLayers();
const promises = [];
layerNames.forEach(function(layerName) {
promises.push(getRecord(cell_date));
});
const cell_records = await Promise.all(promises);
cell_records.forEach(function(cell_record, idx) {
cell_date = layerNames[idx].substring(3)+"_"+window['currentImage'].substring(17,25);
console.log(cell_date+":");
console.log("Matches: "+cellRecord.length);
console.log("testAsyncAwaitFunction response: "+JSON.stringify(cellRecord));
})
}
замените getRecord
на это
function getRecord(cell_date) {
return $.ajax({
url: 'rec/getRecord/'+cell_date,
type: 'get',
dataType: 'json'
}).then(function(response){
console.log("getRecord response: "+JSON.stringify(response));
return response['data'];
});
}
И удалите оба ключевых слова async
и await
из любого места в вашем коде, кроме testAsyncAwaitFunction
в этих двух частях:
async function testAsyncAwaitFunction()
и
let cellRecord = await getRecord(cell_date);
В противном случае они вам не нужны.
Раньше это не работало, потому что ваша функция должна возвращать обещание, содержащее данные. Вы должны прочитать об обещаниях JavaScript . Async / Await является в значительной степени синтаксическим сахаром для них и используется для обработки асинхронного кода. Единственный действительный асинхронный код, который у вас есть, это вызов getRecord
.