Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Как заставить javascript работать нормально? (https://javascript.ru/forum/misc/71891-kak-zastavit-javascript-rabotat-normalno.html)

jaroslav.tavgen 20.12.2017 15:48

Как заставить javascript работать нормально?
 
document.body.innerHTML = "";
for(var i=0;i<3;i++){
    document.body.innerHTML+="Hi! ";
    alert();
}

Как я хочу, чтобы работала программа:

1. Очистила элемент body.
2. Написала "Hi! "
3. Выдала alert.
4. После закрытия alert ещё раз написала "Hi !".
5. Выдала alert.
4. После закрытия alert ещё раз написала "Hi !".
5. Выдала alert.

Как она работает вместо этого, вы видите.

Как сделать так, чтобы программа работала так как я хочу (и как она работала бы в PHP, Java, C и т.д.)?

Очень удивил stackoverflow: https://stackoverflow.com/questions/...78675_47905481

Я думал, что мой вопрос настолько базовый, что мне немедленно дадут ссылку на матчасть. Вместо этого они пишут, что мой вопрос - дубликат вопроса "Давай покрасим холодильник в чёрный цвет" и предлагают кучу решений, которые НЕ РАБОТАЮТ.

Aetae 20.12.2017 16:28

В firefox проблемы нет. Closed: Worksforme. :)
Пишите письма в багтреккер хрома.)

Вообще причина, очевидно, в том, что вызов alert почему-то не считается хромом достаточной причиной для перерисовки. В обычном случае действительно не имеет смыла перерисовывать страницу после каждого шага цикла, т.к. цикл неделимая операция, но по логике вещей alert или какой-нить yield должен таки тригерить это действие.
Принудительный requestAnimationFrame, конечно порешает проблему, но, имхо, данная ситуация если не баг то хреновый код. (Полагаю причина в принципиальном презрении к самому alert:) )

jaroslav.tavgen 20.12.2017 16:46

Цитата:

Сообщение от Aetae (Сообщение 473361)
В firefox проблемы нет. Closed: Worksforme. :)
Пишите письма в багтреккер хрома.)

Вообще причина, очевидно, в том, что вызов alert почему-то не считается хромом достаточной причиной для перерисовки. В обычном случае действительно не имеет смыла перерисовывать страницу после каждого шага цикла, т.к. цикл неделимая операция, но по логике вещей alert или какой-нить yield должен таки тригерить это действие.
Принудительный requestAnimationFrame, конечно порешает проблему, но, имхо, данная ситуация если не баг то хреновый код. (Полагаю причина в принципиальном презрении к самому alert:) )

У меня в Firefox работает абсолютно так же.

Aetae 20.12.2017 16:54

Цитата:

Сообщение от jaroslav.tavgen (Сообщение 473363)
У меня в Firefox работает абсолютно так же.

Абсолютно также это как?)
http://ajitae.tk/test/2.html
FF57.0.2 64bit win7, win8 - всё как надо.

jaroslav.tavgen 20.12.2017 17:04

Цитата:

Сообщение от Aetae (Сообщение 473370)
Абсолютно также это как?)
http://ajitae.tk/test/2.html
FF57.0.2 64bit win7, win8 - всё как надо.

Да, прошу прощения, это я перепутал. Всё правильно. Спасибо большое, за ответ! Я посмотрю, как моя программа (не эта, а настоящая) работает в Firefox, и тогда возможно поподробнее напишу

jaroslav.tavgen 20.12.2017 17:32

Всё ясно, в моей программе была ошибка совсем другого плана.

Aetae, спасибо большое!

jaroslav.tavgen 20.12.2017 17:53

И все-таки вопрос у меня есть.

document.body.innerHTML = "";
for (var i=0;i<1000000;i++){
    document.body.innerHTML += "a";
}

Пока цикл не отработает миллион раз, на экран ничего не будет выведено.

А как сделать так, чтобы он добавлял по одной буковке за раз?

Белый шум 20.12.2017 18:51

<html><body></body></html>
<script>
document.body.innerHTML = "";
var end=500;
(function tick(i) {
   document.body.innerHTML += "a";
   if(i<end) setTimeout(tick.bind(null, i+1), 1);
})(0);
</script>

MallSerg 20.12.2017 19:00

Цитата:

Сообщение от jaroslav.tavgen (Сообщение 473380)
А как сделать так, чтобы он добавлял по одной буковке за раз?

В цикле практически ни как.

JS строго однопоточен. т.е. использовать несколько потоков в одном контексте исполнения невозможно.
в JS невозможно ограничить область видимости одного потока от области видимости другого потока (глобальный объект, цепочка прототипов) доступны всем и всегда. Изменения данных в одном потоке сделают непредсказуемым результат работы в другом потоке.

самый простой способ обойти блокировку других задач (рендеринга) пока работает долгий код это разбить задачу вызовами асинхронной функции setTimeout (задача,0) т.е. запустить/продолжить задачу после того как браузер сделает все ожидающие операции.

небольшой пример
<body><script>
function repeat (fun,size){
	+function asd (){
		fun();
		if (size % 110 == 0) document.body.innerHTML += "<br>";
		if ( --size > 0) setTimeout (asd,0);
	}();
}
function idiotizm (){
	document.body.innerHTML += "a";
}
repeat (idiotizm , 6000);
</script>

Aetae 20.12.2017 22:03

Добавлю для ясности: однопоточность означает, что пока поток занят циклом, он физически не может ничего рисовать. Цикл - единичный неделимый блок. Чтобы гарантировано, сразу по возможности(fps), результат появлялся на экране - придумали requestAnimationFrame, но за отсутствием(старый ослик) и setTimeout пойдёт.


Часовой пояс GMT +3, время: 14:32.