Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   setTimeout/setInterval - неожиданное поведение (https://javascript.ru/forum/misc/20782-settimeout-setinterval-neozhidannoe-povedenie.html)

RUVATA 17.08.2011 08:55

setTimeout/setInterval - неожиданное поведение
 
Всем доброго времени суток...
IE8\HTML+JS+ActiveX ; Страничка с согласия юзверя работает через объекты ActiveX c MS Excel и файловой системой, а пока она это делает, я хотел бы показывать некую анимацию, пусть банально менять текст в <textarea>...
Вычитав, что о многопоточности говорить не приходится, начал копать в сторону асинхронности, и вот я "раскуриваю" setTimeout/setInterval реф которых утверждает что они предназначены для асинхронного вызова функций, казалось бы "то что надо!", а нет... или я не уловил суть (хотя с асинхронностью знаком не по наслышке на серверном Node.js)
так вот...
пуcть в теле документа имеем некую функцию myStatusBar() , она у нас занимается некой анимацией (добавляет точку к <textarea>*.value) -
setInterval(function(){myStatusBar();},500);

далее собственно запускаем наш тяжеловесный процесс работы с Excel и файловой системой назовем его myHeavyProcess()(это или последовательный вызов нескольких функций, или вызов одной, которая сама вызывает все последующие //PS: в средем 5-6 сек.)
вот что у нас вышло
setInterval(function(){myStatusBar();},500);
myHeavyProcess();

что ожидалось: функция myStatusBar() будет выполняться каждые 0,5 сек. в то время как будет выполняться myHeavyProcess()
что вышло: функция myStatusBar() выполнится один раз, потом будет "шурупить" myHeavyProcess() все свои 5-6 сек. без какой либо анимации, и как только она закончит опять выполнится myStatusBar()...

Ну и какая-же это асинхронность ?

Kolyaj 17.08.2011 09:03

Цитата:

Сообщение от RUVATA
Ну и какая-же это асинхронность ?

А где вы написали, что myHeavyProcess у вас асинхронная? А раз она не асинхронная, то она занимает поцесс, пока выполняется. Раз она занимает процесс, все остальные ждут, пока она выполнится.

RUVATA 17.08.2011 09:08

Ладно, вот так...
setInterval(function(){myStatusBar();},500);
setTimeout(function(){myHeavyProcess();},1000);

на выходе то-же самое...

RUVATA 17.08.2011 09:13

Я уверен, что я где-то недопонимаю "евангелия" клиентского программирования...
Передо мной стоит задача рисовать анимацию пока выполняются сложные расчеты и взаимодействия, подскажите что мне для этого надо сделать?

Kolyaj 17.08.2011 09:33

setTimeout/setInterval не создают новый процесс, код выполняется в том же процессе, но с задержкой. Соответственно, если процесс занят, то ничего другое выполниться не сможет.

Цитата:

Сообщение от RUVATA
Передо мной стоит задача рисовать анимацию пока выполняются сложные расчеты и взаимодействия, подскажите что мне для этого надо сделать?

Поделить сложные расчёты на куски, между которыми делать паузы.

melky 17.08.2011 09:58

Цитата:

Сообщение от RUVATA (Сообщение 121004)
Я уверен, что я где-то недопонимаю "евангелия" клиентского программирования...
Передо мной стоит задача рисовать анимацию пока выполняются сложные расчеты и взаимодействия, подскажите что мне для этого надо сделать?

хотите настоящей асинхронности - гуглите Web Workers

или переписывайте код с шагами,как сказал Kolyaj

RUVATA 17.08.2011 10:40

Web Workers - заманчиво, а самое главное НАДО (я пока не столкнулся с "клиенто-шаманизмом" думал, что таки есть нечто подобное уже давно)
но к сожалению в "осле" который мне требо в связи с ActiveX, даже наметок для Web Workers нет, есть правда эмулятор
но это в общем-то костыли :))
Я решил так: добавлю к прототипу функции метод вызывающий функцию ответственную за всю анимацию на страничке, ну и собственно, разбивать код на более мелкие фрагменты, между которыми "взывать" к анимации...
PS: косяк в том, что это тяжело сделать равномерно.

RUVATA 17.08.2011 11:54

И все равно анимации не выходит...
Даже если я линейно в программу повтыкал вызов функции которая рисует анимацию, никаких таймаутов и прочего - все линейно...
Все равно... то есть то нет... такое чувство, что она не успевает отрисовываться что-ли... ну в чем может быть дело ?
Cмысл такой: есть некий element пусть
<textarea id='satus'>Здесь хочу писать статус выполнения</textarea>

ну делаю банально
myAnimation('выполняется myFunction1')
myFunction1()
    myAnimation('выполняется myFunction2')
myFunction2()
    myAnimation('выполняется myFunction3')
myFunction3()
    myAnimation('выполняется myFunction4')
myFunction4()
    myAnimation('выполняется myFunction5')
myFunction5()
    myAnimation('выполняется myFunction6')
myFunction6()
    myAnimation('Готово')

function myAnimation(text){
var element = document.getElementById("status");	
element.value = text
};

//все myFunction*() это какие ни будь вычисления/манипуляции с объектами ActiveX

вешаем все это на button и понеслась...
все myFunction*() успешно выполняются одна за одной... а вот в 'satus' отрисовывается только 'выполняется myFunction1'... и висит, потом когда все расчеты закончились быстро мелькает 'выполняется myFunction6' и 'Готово'

В чем дело... как заставить отрисовываться в обязательном порядке ?

Kolyaj 17.08.2011 12:01

Цитата:

Сообщение от RUVATA
myAnimation('выполняется myFunction1')
myFunction1()
myAnimation('выполняется myFunction2')
myFunction2()
myAnimation('выполняется myFunction3')
myFunction3()
myAnimation('выполняется myFunction4')
myFunction4()
myAnimation('выполняется myFunction5')
myFunction5()
myAnimation('выполняется myFunction6')
myFunction6()
myAnimation('Готово')

Вот это всё выполняется разом, без перерыва, браузеру тут некуда втиснуться, чтобы отрисовать то, что выводится.

RUVATA 17.08.2011 12:48

как быть ?

Kolyaj 17.08.2011 12:53

Каждую следующую myFunction вызывать через setTimeout

RUVATA 17.08.2011 14:24

здесь представлен список свойств обращение к которым вызывает немедленный redraw элемента:
1. offsetTop, offsetLeft, offsetWidth, offsetHeight,
2. scrollTop/Left/Width/Height,
3. clientTop/Left/Width/Height,
4. getComputedStyle() или currentStyle в IE.
...фактически в IE8 100% работают только 1-ые...
На одном из англ.форумов вычитал
Цитата:

I use the following:

elm.style.display=”none”;
var redrawFix = elm.offsetHeight;
elm.style.display=”block”; // or other value if required

This works in all browsers I have needed it for – Opera, Konqueror, Safari and IE (including IE8 RC1 for which I just needed a redraw fix too). I haven’t ever needed it for Firefox though..
хотя у меня работает и без изменения свойства display, далее автор утверждает что именно такая конструкция работает всегда.

RUVATA 17.08.2011 14:28

Цитата:

Каждую следующую myFunction вызывать через setTimeout
без толку... пробовал...
Дело было в баге самого IE :
пока идет непосредственная работа с COM-компонентами в моем случае ActiveX, IE для повышения производительности отключает все вcтроенные redraw / reflow... хочешь что-то отрисовать - вызывай его принудительно. ("как?" - постом выше)

RUVATA 18.08.2011 13:25

И так окончательная точка
JavaScript у клиента в данный момент (не берем в расчет Web Workers которые еще "будующее") не выполняется асинхронно никак.
setTimeout и setInterval - вопреки рефу, псевдоасинхронность т.е.
управление не совмещает выполнение кодов разных функций за один такт...

Kolyaj 18.08.2011 13:32

Цитата:

Сообщение от RUVATA
setTimeout и setInterval - вопреки рефу, псевдоасинхронность т.е.

Нормальная там асинхронность. Вы по какой-то причине считаете, что асинхронность == многопоточность, что не есть правда.

popov654 19.08.2011 00:46

********************

Gvozd 19.08.2011 04:02

Цитата:

Сообщение от RUVATA
setTimeout и setInterval - вопреки рефу, псевдоасинхронность т.е.
управление не совмещает выполнение кодов разных функций за один такт...

когда одновременно выполняются две функции - это многопоточность.
а ассинхронность(в браузерном JS) - явление строго однопоточное.
ассинхронность позволяет положить функции в очередь, до наступления события, когда они смогут выполниться. При этом они вовсе не обязаные выполнятся одновременно, и даже не гарантируется что они выполнятся в указанном вами порядке(в случае когда они должны сработать "одноврменно").

RUVATA 19.08.2011 08:12

Вам как JavaScript-ерам должна быть знакома технология серверного JavaScript - NODE.js, вот здесь часть идеологии асинхронности...
Более того, не хотел бы с вами спорить, но видимо вы заблуждаетесь...
Цитата:

Сообщение от Gvozd
когда они смогут выполниться.

не когда они смогут, а тогда когда они должны будут выполниться - в этом суть асинхронности (таймеры и коллбэки).
Т.е. по наступлению события или таймера, исполнение текущего контекста приостанавливается, и исполняется контекст назначенный, после чего возобновляется выполнение текущего...
В нашем-же случае setTimeout и setInterval являются таймерами, но они не останавливают выполнение основного контекста, а покорно ждут пока контекст исполнится...

float 19.08.2011 08:34

Цитата:

в этом суть асинхронности
суть асинхронности в том, что функция будет выполняться в неизвестный момент времени.
Цитата:

а тогда когда они должны
никто ничего не должен. в том то и дело.

RUVATA 19.08.2011 08:46

вот некий код для "разбора полетов"
<html>
 <head> </head>
 
<body>
 <script type="text/javascript">
		
		AsyncTest()
	
	function AsyncTest(){
		var someText = ''

		setInterval(function(){someText = someText + '-AsyncInjection-';}, 12)

		for(var i = 0; i < 20; i++){
		  someText = someText + '-MainTheadInjection-'
		};

		alert(someText)
	}
	</script>
</body>

 <html>

что-же увидите на выходе ?
Цитата:

-MainTheadInjection--MainTheadInjection--MainTheadInjection--MainTheadInjection--MainTheadInjection--MainTheadInjection--MainTheadInjection--MainTheadInjection--MainTheadInjection--MainTheadInjection--MainTheadInjection- ...
Ну и где-же асинхронный вызов ? хотя если бы код выполнялся асинхронно мы бы увидели:
Цитата:

-MainTheadInjection--MainTheadInjection--AsyncInjection--MainTheadInjection--MainTheadInjection--MainTheadInjection--MainTheadInjection--AsyncInjection--MainTheadInjection--MainTheadInjection--MainTheadInjection--AsyncInjection- ...
Чувствуете разницу ?
проведите аналогичный эксперимент в NODE.js :)

RUVATA 19.08.2011 08:53

Цитата:

Сообщение от float
никто ничего не должен. в том то и дело.

зашибись :) а зачем тогда у функций setTimeout и setInterval второй параметр, которым задается отсрочка или интервал ?
если:
Цитата:

Сообщение от float
функция будет выполняться в неизвестный момент времени.

Для красоты ?
Вот оф.реф для setInterval
Цитата:

Сообщение от float
Calls a function repeatedly, with a fixed time delay between each call to that function.

здесь что-то сказано про неопределенность ?

float 19.08.2011 09:01

var t = Date.now();
var str = '';
for(var i = 0; i<20; i++) {
    str +='afa';
}
alert(Date.now()-t);

float 19.08.2011 09:06

Цитата:

проведите аналогичный эксперимент в NODE.js
тожесамое...

RUVATA 19.08.2011 09:07

и... :)
мне alert-нуло '0'
это вы к чему ?
где тут асинхронность и вообще инструкция в 6-ой строке листинга 'str' это что ?

float 19.08.2011 09:16

Цитата:

и...
к тому, что 0 это приблизительно время выполнения вашей функции, а через интервал у вас только спустя 12 мс вызовется.
Цитата:

и вообще инструкция в 6-ой строке листинга 'str' это что
мусор из консоли завалялся:)

Kolyaj 19.08.2011 09:28

Цитата:

Сообщение от RUVATA
Т.е. по наступлению события или таймера, исполнение текущего контекста приостанавливается, и исполняется контекст назначенный, после чего возобновляется выполнение текущего...

Вы это сами только что придумали или вычитали где? Объясняю на пальцах

setTimeout(foo, 500);
bar();

Допустим функция bar выполняется 2 секунды. Тогда вопреки вашему желанию функция foo выполнится не через пол секунды, а через две, когда освободится поток. В общем случае запись setTimeout(foo, n) означает "запустить функцию foo не раньше чем через n миллисекунд", а не "запустить функцию foo через n миллисекунд".

RUVATA 19.08.2011 10:02

PS: :) кстати по поводу NODE.js я погорячился setTimeout и setInterval работают точно так-же ... виноват... зато callback-и прерывают выполнение как и ожидается
var events = require("events");
var emitter = new events.EventEmitter; // создаём генератор
var someText = '';

// задаём обработчик пользовательского события "event1"
emitter.on("event1", function(data) {
    if(){}
	someText = someText + '-Async-'
});

for(var i = 0; i < 20; i++){
 someText = someText + '-MainThead-';
 emitter.emit("event1");
}

console.log(someText)

...
PPS: Вы безусловно правы ВСЕ... вы описываете реальное положение вещей. НО ЭТО НЕ АСИНХРОННОСТЬ !
Нельзя функцию с отложенным вызовом называть асинхронной. Это просто функция с отложенным вызовом и не более того.
Асинхронно - это не синхронно... то есть код будет выполняться в одном потоке но в смешанном режиме, по крайней мере такова асинхронность в низкоуровневом программировании.
когда выполнение двух функции (func1 и func2) в асинхронном режиме выглядит как-то так:
Выполняется инструкция из func1
Выполняется инструкция из func2
Выполняется инструкция из func1
Выполняется инструкция из func2
Выполняется инструкция из func2
Выполняется инструкция из func1
и т.д.
(правила скрещивания обусловлены платформой, ресурсами под инструкцию и т.д.)
они не паралельны, но и не синхронны... они асинхронны.

Здесь-же мы наблюдаем псевдоасинхронность...

Kolyaj 19.08.2011 10:10

Цитата:

Сообщение от RUVATA
зато callback-и прерывают выполнение как и ожидается

Разумеется, ведь emit синхронный. Откуда там асинхронности взяться?

float 19.08.2011 10:16

Цитата:

они не паралельны, но и не синхронны... они асинхронны.
:haha:
Многозадачность

Kolyaj 19.08.2011 10:39

Давайте по порядку. Асинхронная функция -- такая функция, которая сразу передаёт управление вызвавшему её коду, но продолжает в это время что-то делать и результат своей работы сообщает позже. Разумеется, продолжает что-то делать она в другом потоке, но этот другой поток реализован или на уровне платформы (XMLHttpRequest в браузере), или на уровне ОС (i/o в NodeJS). Сам JavaScript при этом остаётся однопоточным.

В случае использования setTimeout второй поток не нужен. Функция ничего не делает, пока ждёт запуска переданной в setTimeout функции, а ничего не делать можно и в одном потоке :)

RUVATA 22.08.2011 15:04

Цитата:

Сообщение от Kolyaj
которая сразу передаёт управление вызвавшему её коду, но продолжает в это время что-то делать и результат своей работы сообщает позже. Разумеется, продолжает что-то делать она в другом потоке

Kolyaj, расставил все точки над "ё"...
:agree: Я действительно увлекся спором, не обладая достаточной базой для его поддержания...
хотя в итоге - "В JavaScript не исполняется асинхронно, как не крути"
с чего собственно все и началось :yes:

Solovei95 23.08.2011 16:43

function time(){
setTimeout(time,500); //Запускаем интервал
func(); //Запускаем другую функцию
}

Это тебе о чем нибудь говорит?


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