Этот вопрос лучше всего понять, если понять, как node.js использует цикл обработки событий. По своей сути, node.js запускает ваш Javascript в одном потоке и использует цикл событий, чтобы управлять завершением событий вне этого единственного потока, таких как таймеры, сетевые операции, операции с файлами и т. Д. *
Давайте сначала начнем с очень простого while()
цикла:
let done = false;
setTimeout(() => {
done = true;
}, 100);
while(!done) {
// do whatever you want here
}
console.log("done with while loop"); // never gets called
На первый взгляд, вы можете подумать, что цикл while
будет работать в течение 100 мс, а затем done
будет установлен в значение true и цикл while
завершится. Это не то, что происходит. На самом деле это бесконечный цикл while. Он запускается, работает и работает, а переменная done
никогда не устанавливается на true
. console.log()
в конце никогда не запускается.
У него есть эта проблема, потому что setTimeout()
является асинхронной операцией, и она сообщает о своем завершении через цикл обработки событий. Но, как мы описали выше, node.js запускает свой Javascript как однопоточный и получает следующее событие из цикла событий только тогда, когда этот единственный поток завершает свою работу. Но while
не может завершить то, что он делает, пока done
не будет установлен в true
, а done
не может быть установлен в true, пока цикл while
не завершится. Это противостояние, а цикл while работает вечно.
Итак, в двух словах, пока выполняется какой-либо цикл, НИКАКАЯ асинхронная операция никогда не обработает свой результат (если только он не использует await
внутри цикла, который является чем-то другим). Асинхронные операции (или все, что использует цикл событий) должны ждать, пока не завершится текущий работающий Javascript, и затем интерпретатор может вернуться к циклу событий.
Ваш цикл while имеет ту же проблему. spotifyApi.searchTracks()
- это асинхронная операция, которая возвращает обещание, и все обещания сообщают свои результаты через очередь событий. Итак, у вас такое же противостояние. Ваш обработчик .then()
не может быть вызван, пока не завершится цикл while
, но ваш цикл while
не может завершиться, пока не будет вызван обработчик .then()
. Ваш while
цикл будет просто бесконечно повторяться до тех пор, пока вы не исчерпаете какой-то системный ресурс, и ваши обработчики .then()
никогда не получат шанс выполнить.
Поскольку вы не включили в свой обработчик запросов код, который фактически производит какой-либо результат или действие (все, что он делает, это просто изменяет некоторые локальные переменные), неясно, что именно вы пытаетесь выполнить и, следовательно, как лучше напишите этот код.
У вас, кажется, есть N поисков, и вы регистрируете что-то в каждом поиске. Вы можете сделать их все параллельно и просто использовать Promise.all()
, чтобы отслеживать, когда они все сделаны (без while
петли вообще). Или вы можете упорядочить их, чтобы запустить один, получить его результат, а затем запустить другой. Ваш вопрос не дает нам достаточно информации, чтобы знать, какой вариант будет наилучшим.
Вот одно из возможных решений:
Последовательность операций с использованием async / await
Здесь обработчик запроса объявлен async
, поэтому мы можем использовать await
внутри цикла while
. Это приостановит цикл while
и позволит обрабатывать другие события в ожидании разрешения обещания.
app.get('/process', ensureAuthenticated, async function (req, res) {
let init_array = text.split(" ");
let modtext = init_array;
while (init_array.length != 0) {
try {
let data = await spotifyApi.searchTracks(modtext.join(" "));
console.log(data.body.tracks.items[0].name);
for (let i = 0; i < modtext.length; i++) {
init_array.shift();
}
modtext = init_array;
} catch (err) {
console.log("No song");
modtext.pop();
}
}
res.redirect('/');
});