Прежде всего мы должны понять, что JS однопоточный. Код вашей программы обрабатывается только одним потоком. Он может запускать только один фрагмент кода (скажем, функцию) за раз. Помня об этом факте, давайте попробуем выяснить, что происходит в вашем коде.
async fetchNewJokes() {
let newJokes = [];
while (newJokes.length < 10) {
/*1*/ const {data} = await axios.get('https://icanhazdadjoke.com/', {
headers: {Accept: 'application/json'}});
/*2*/newJokes.push(data.joke);
this.setState({jokes: newJokes});
}
}
JS выполняет эту функцию, пока не встретит await
в строке \*1*\
. Затем он выполняет axios.get()
и возвращается к основному коду, не дожидаясь результата axios.get()
.
Далее он продолжает работать с другим кодом, делая другие полезные вещи, такие как рендеринг, обработка пользовательского ввода и так далее. Время от времени он проверяет завершено или нет axios.get()
.
Когда axios.get()
завершено, он присваивает результат значению data
и продолжает выполнение этой функции со строки \*2*\
. На следующей итерации while
l oop он снова встречает await
и повторяет действия, описанные выше. И то же самое происходит для каждого шага while
l oop.
Теперь давайте посмотрим на второй фрагмент кода.
fetchNewJokes() {
let newJokes = [];
while (newJokes.length < 10) {
axios.get('https://icanhazdadjoke.com/', {
headers: {Accept: 'application/json'}}).then(()=>{
newJokes.push(data.joke);
this.setState({jokes: newJokes});
});
}
}
JS выполняет эту функцию и выполняет axios.get()
. Теперь для выполнения .then()
JS необходимо время от времени проверять, завершено ли axios.get()
. Но не может!
JS поток занят выполнением while
l oop. Вы не даете ему времени заниматься чем-то другим. Он продолжает вызывать axios.get()
снова и снова, не имея возможности проверить результат. Кроме того, поскольку JS занят выполнением l oop, у него нет времени на рендеринг. L oop потребляет все больше и больше ресурсов. Вот почему браузер зависает.
Ну и какое решение? @gdh уже дал вам один из них. Но если вам нужно внести меньше изменений в свой код, просто не полагайтесь на результат Promise
в условии l oop.
fetchNewJokes() {
for (let i=0; i<10; i++) {
axios.get('https://icanhazdadjoke.com/', {
headers: {Accept: 'application/json'}}).then(()=>{
this.setState({jokes: this.state.jokes.concat(data.joke)});
});
}
}
В этом случае функция выполняет axios.get()
десять раз и возвращает управление основному коду.