Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 1.0/2.0 (http://www.flasher.ru/forum/forumdisplay.php?f=93)
-   -   onClipEvent (http://www.flasher.ru/forum/showthread.php?t=79666)

Beta-tester 12.05.2006 20:13

onClipEvent
 
Приветствую!
Напишите пожалуйста как лучше заменить конструкцию -OnClipEvent(enter frame){....
И опишите почему её не следует использовать(с тормозаааааааами я уже встретился !!!)
В поиске был(во всех темах просто говорят, что это плохо)!
P.S. Заранее благодарен!

artcraft 12.05.2006 20:15

это зависит от задачи

iNils 12.05.2006 20:23

Цитата:

Сообщение от Beta-tester
Приветствую!
Напишите пожалуйста как лучше заменить конструкцию -OnClipEvent(enter frame){....
И опишите почему её не следует использовать(с тормозаааааааами я уже встретился !!!)
В поиске был(во всех темах просто говорят, что это плохо)!
P.S. Заранее благодарен!

меняется на
Код:

мувиклип.onEnterFrame = function () {
//// действие
}

код находится на таймлайн.
OnClipEvent плох потому что, надо тратить время на поиск кода среди мувиклипов, хранить код в одному месте удобнее и конструкция моральна устарела.

Beta-tester 12.05.2006 20:30

Спасибо!
А будет ди этот код работать быстрее?
Ещё вопрос у моего мува fps=12, значит onEnterFrame будет работать 12 раз?А можно например 2 раза(с дополнительной проверкой я сделал, но может есть другой способ)(вообще хочу понизить нагрузку, а то мув тормозит!)
P.S. Заранее биг спасибо!!!!!!!

Бармалей 12.05.2006 20:36

если не хочешь вызывать функцию в каждом кадре, используй setInterval().

artcraft 12.05.2006 20:51

причиной тормозов может быть не только onEnterFrame

Homo Sapiens 12.05.2006 20:55

По смыслу, onEnterFrame, "когда загружается кадр". Это событие происходит каждый раз при загрузке нового кадра, при fps 12 оно в идеале будет возникать 12 раз в секунду. (Если анимация или вычисления сложные, оно будет возникать реже)
Отказ от on(ClipEvent) позволит сделать твои ролики быстрее.

Nirth 12.05.2006 20:56

Самое выгодное имхо в испльзовании обработчика события onEnterFrame вместо onClipEvent(enterFrame) в том, что его можно удалять и создавать заново.

Beta-tester 13.05.2006 19:26

Nirth ты не мог бы поподробнее описать динамическое добавление удаление(эта тема может помочь мне повысить скорость)
Заранее спасибо!
Homo sapiens спасибо за интересный ответ!
Т.е onClipEvent при любых обстоятельствах выполняется n раз(n=fps), а onEnterFrame динамически в зависимости от нагрузки(я правильно понял?), если это так то жить мне станет легче :)

Nirth 13.05.2006 19:33

Beta-tester почитай в хелпе про delete

Beta-tester 13.05.2006 21:24

Вот этот delete:
delete (reference); ?
Или какой-то другой?

Nirth 13.05.2006 21:26

в хелпе только один delete

Madasan 13.05.2006 22:29

Есть еще одна полезность заставляющая отказаться от onClipEvent. Это область видимости переменных. Если мы запишем такой код в главной временной шкале,
Код:

var myVar = 'ok';
myClip.onEnterFrame = function() {
        trace(myVar);
};

То можем убедиться, что наша переменная замечательно видна. А если мы наш энтерфрейм запишем вот так:
Код:

onClipEvent (enterFrame) {
        trace(myVar);
}

То наша переменная, если она определена вне клипа просто так не найдется, нужно будет писать что-то типа trace(_root.myVar); или trace(this._parent.myVar); чтобы флэш ее нашел. Таким образом определив функцию вне клипа к которому мы ее прилепляем, мы обеспечиваем область видимости переменных как той временной шкалы, где определяем функцию, так и переменных принадлежащей временной шкале клипа из которого будем эту функцию вызывать, которые будут видны как this.myVar . Конечно может это и не очень хорошо заставлять флэш просматривать все доступные области видимости, вместо того, чтобы указать ему конкретный путь, но зачастую это удобно! :D

--а удалять обрабочик onEnterFrame(равно как и все остальные функции)
мона так:
Код:

delete onEnterFrame;
или так:
Код:

onEnterFrame=null
В последнем случае мы его не удаляем, а просто делаем его пустым, то есть он есть, но не содержит ничего, а следовательно и не выполняется.

etc 14.05.2006 15:15

Насчёт "не выполняется" есть некоторое сомнение, но проверить на практике можно вот так:
Код:

this.createTextField("fps_txt", 0, 10, 10, 100, 20);
fps = 0;
clearFPS = function () {
        fps_txt.text = fps;
        fps = 0;
};
onEnterFrame = function () {
        fps++;
};
setInterval(clearFPS, 1000);
for (var i = 0; i<10000; i++) {
        var mc = this.createEmptyMovieClip("test_"+i+"mc", i+1);
        mc.onEnterFrame = function () {
                this._x++;       
        };
       
}
for (var i=0;i<10000;i++) {
        var mc = this['test_'+i+'mc'];
        mc.onEnterFrame = null; // 55-65 fps
        //delete mc.onEnterFrame; // 100-125 fps
}

Вывод: используйте delete.

з.Ы. И не смотрите на значения чисел в цикле.

з.Ы.Ы. В примере установлено 120 fps.

Madasan 15.05.2006 03:37

Цитата:

Сообщение от ETC
Насчёт "не выполняется" есть некоторое сомнение, но проверить на практике можно вот так:

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

Сообщение от Madasan
В последнем случае мы его не удаляем, а просто делаем его пустым, то есть он есть, но не содержит ничего, а следовательно и не выполняется.

По тому что он есть, он и занимает ресурсы. :)
Цитата:

Сообщение от ETC
Вывод: используйте delete.

А вот насчет вывода есть сомнение. Если уж брать такие мегаколичества объектов, то можно также привести пример с обратным эффектом:
Код:

this.createTextField("fps_txt", 0, 10, 10, 100, 20);
for (var i = 0; i<10000; i++) {
        var mc = this.createEmptyMovieClip("test_"+i+"mc", i+1);
}
function enteRFrame() {
        this._x++;
}
onEnterFrame = function () {
        time = getTimer();
        for (var i = 0; i<10000; i++) {
                var mc = this['test_'+i+'mc'];
                //mc.onEnterFrame = null;
                delete mc.onEnterFrame;
                mc.onEnterFrame = enteRFrame;
        }
        fps_txt.text = getTimer()-time;
};

Когда мы полностью удалии объект, то если он нам еще раз понадобиться, его придется создавать заново, а это более напряжно, чем просто присвоить новое значение. Так что вывод можно сделать такой. Если нужно с достаточно большой частотой удалять и создавать этот самый онЭнерФрейм, то можно просто присваивать null, если же нужно освободить ресурс на какой-то промежуток времени или на совсем, то лучше использовать delete.

Homo Sapiens 15.05.2006 08:44

2 ETC, странный у тебя какой то тест... Я его себе скопипастил, запустил... а он просто повесил плейер... Ты его хоть тестировал?

По поводу присвоение null или delete, насколько я понимаю, это одно и тоже, в первом случае объект напрямую помечается для удаление сборщиком мусора, во втором, при очередном проходе, сборщик найдя нулевой указатель сам удалит объект. С учётом того, что сборщик мусора проходит с определённым периодом, вряд ли в случае delete объект будет удалён раньше...

Homo Sapiens 15.05.2006 09:03

Код:

var count = 0;
var inter;
var res = 1;

_root.onEnterFrame = function()
{
        count++;
}

function Stop()
{
        //delete test.onEnterFrame;
        test.onEnterFrame = null;
        trace(count);
        clearInterval(inter);
        Start();
        inter = setInterval(StopAll, 5000);
}

function StopAll()
{
        clearInterval(inter);
        trace(count);
        trace(res);
        delete _root.onEnterFrame;
}

var test = this.createEmptyMovieClip("test", 1);
test._x = 300;
test._y = 300;
test.onEnterFrame = function()
{
        res += Math.round(Math.random() * Math.cos(Math.random())) - Math.exp(Math.random());
        test._rotation += 0.70;
        test.clear();
        test._alpha = random(100);
        test.lineStyle(1, 0x000000, 100);
        test.beginFill(random(0xFFFFFF), 100);
        test.moveTo(0, 0);
        test.lineTo(0, 600);
        test.curveTo(630, 650, 510, 520);
        test.lineTo(0, 0);
}

inter = setInterval(Stop, 5000);

Частота кадров - 100

Homo Sapiens 15.05.2006 09:18

Разница получается минимальная. Ради интереса можно закомментить test.clear();

etc 15.05.2006 13:23

Конечно тестил, надо было не прерывать.

Madasan, твой пример мне непонятен, this в функции enteRFrame куда ссылается? delete удаляет саму функцию из памяти, а не объект, который её содержит. Тем более, ты после удаления функции (которой ещё нет), присваиваешь ей значение и конечно же видишь тормоза. Я не вижу смысла удалять функцию перед тем, как заново ей присваивать значение. Как правило, если нужно остановить onEnterFrame, то останавливается он не на время выполнения двух строк кода, а на гораздо большее. Возможно, постоянно медленно работающее приложение тебя устроит больше, чем приложение, которое, хоть и подтормаживает при выполнении действий с onEnterFrame, но после их выполнения работает ощутимо быстрее...

null не удаляет функцию из памяти, это можно увидеть в trace:
Код:

Movie Clip: Target="_level0.test_5014mc"
Variable _level0.test_5014mc.onEnterFrame = null
Movie Clip: Target="_level0.test_5015mc"

Соответственно, если клип имеет у себя onEnterFrame, то значит он подписан на enterFrame, со всеми вытекающими...
Даже если не подписан, всё равно у клипа есть переменная, которая в любом случае отжирает память.

А вот результат с delete:
Код:

Movie Clip: Target="_level0.test_6815mc"
Movie Clip: Target="_level0.test_6816mc"
Movie Clip: Target="_level0.test_6817mc"

Комментировать не буду. Homo Sapiens, видна разница между delete и null?

Функцию нужно убить, если она вам не нужна, в просто так забивать null-ем память лишний раз не стоит.

Кто-то скажет, что мол, такого количества объектов врядли у кого-то будет (а падение производительности в два раза ощутимо). Согласен, но если часть onEnterFrame выполняет сложные вычисления, а другая часть просто отжирает процессорное время, ничего не делая, то потом можно не удивляться, почему тормозит...

etc 15.05.2006 13:28

Homo Sapiens, а что иллюстрирует твой пример? У тебя один объект, после выполнения действий ты или удаляешь или присваиваешь null функции. Но count тут причём? С одним объектом разница между null и delete не ощутима в плане производительности (тем не менее, в памяти остаётся onEnterFrame, если использовать null)

Madasan 15.05.2006 15:37

Цитата:

Сообщение от ETC
Madasan, твой пример мне непонятен, this в функции enteRFrame куда ссылается?

this ссылается на объект активации функции, откуда мы ее вызовем, такой и будет this. В данном случае это будет mc
Цитата:

Сообщение от ETC
delete удаляет саму функцию из памяти, а не объект, который её содержит.

В моем примере, onEnterFrame содержит ссылку на функцию enteRFrame, и что же в этом случае удаляет delete? В твоем примере, ты присваиваешь каждому мувику отдельную функцию, и у тебя их соответственно в памяти висит столько, сколько мувиков ты и создаешь. У меня одна функция, и onEnterFrame каждого мувика ссылается на нее, так что delete onEnterFrame никак не может ее удалить, он удаляет только ссылку.
Цитата:

Сообщение от ETC
Я не вижу смысла удалять функцию перед тем, как заново ей присваивать значение.

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

Сообщение от ETC
Как правило, если нужно остановить onEnterFrame, то останавливается он не на время выполнения двух строк кода, а на гораздо большее. Возможно, постоянно медленно работающее приложение тебя устроит больше, чем приложение, которое, хоть и подтормаживает при выполнении действий с onEnterFrame, но после их выполнения работает ощутимо быстрее...

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

Цитата:

Сообщение от ETC
а другая часть просто отжирает процессорное время, ничего не делая, то потом можно не удивляться, почему тормозит...

Так вот, если работник пришел на работу, и в течении какого-то времени ему нечем заняться, то это не значит, что его надо отправлять домой, а потом снова вызывать. Если ему нечего делать всего несколько минут, он может и подождать, а если пауза большая, то его с работы можно пока и удалить.
А так, все правильно , и разница действительно есть и null для того и существует, чтобы переменная была, пусть и пустая, но нам она еще пригодиться.:D

Homo Sapiens 15.05.2006 17:10

Смысл кода такой, что есть два обработчика OnEnterFrame, первый считает число кадров, а второй выполняет некоторые действия, например программное рисование. Через 5 секунд мы отключаем второй обработчик 2 разными способами
Код:

test.onEnterFrame = null;
и
Код:

delete test.onEnterFrame;
и независимо от способа результат не меняется.
2 ETC. Запости как ты трассировал переменные. Кстати, ты не думаешь о том, что обрботчик onEnterFrame вызывается кодом, подобным
Код:

function CallEnterFrame(target)
{
    if(target.onEnterFrame)
        target.onEnterFrame();
}

Разумеется, что этот код написан на C++, но наверняка он имеет подобный вид, и соответственно не имеет значения, определена ли переменная onEnterFrame или она равна null

etc 15.05.2006 17:28

Ctrl+Alt+V я трейсил.
Результат у тебя не меняется в силу того, что при наличии всего одного объекта разница не ощутима.
Функция может и не вызываться, но при null она в памяти есть.

iNils 15.05.2006 18:05

Код:

for (i = 0; i < 2000; i++) {
        this.createEmptyMovieClip ("mc" + i, i);
        this["mc" + i].onEnterFrame = null;
}

загрузка процессора у меня порядка 8-11%
Код:

for (i = 0; i < 2000; i++) {
        this.createEmptyMovieClip ("mc" + i, i);
}

а так 2-4%
кому не нравится отсутствие onEnterFrame во втором примере, может сделать так
Код:

f = function () {
        delete this.onEnterFrame;
};
for (i = 0; i < 2000; i++) {
        this.createEmptyMovieClip ("mc" + i, i);
        this["mc" + i].onEnterFrame = f;
}

будут теже 2-4% (относительно моей машины)

Homo Sapiens 15.05.2006 19:33

2 ETC, спасибо, не знал про это
2 All, ну бог знает, я не знаю наверняка, вполне возможно, что delete работает действительно быстрее...

Madasan 15.05.2006 20:42

Цитата:

Сообщение от Homo Sapiens
2 All, ну бог знает, я не знаю наверняка, вполне возможно, что delete работает действительно быстрее...

Да нет быстрее работает не delete, а весь мувик, когда его освободишь от 2000 пустых энтерфреймов.

etc 15.05.2006 20:44

именно

Nirth 15.05.2006 20:46

Извиняюсь за вопрос....а часто нужно бывает больше 10ти enterFrame'ов?

artcraft 15.05.2006 20:55

мораль проста: просто так одним только энтерфреймом машину не повесишь - надо проявить смекалку :~)

Antares 15.05.2006 21:02

Цитата:

Сообщение от Nirth
Beta-tester почитай в хелпе про delete

Я бы посоветовал вообще доку почитать. Азы объяснять утомляет.

Antares 15.05.2006 21:04

Цитата:

Сообщение от Homo Sapiens
2 All, ну бог знает, я не знаю наверняка, вполне возможно, что delete работает действительно быстрее...

Это же базовый принцип работы garbage collector-а: есть ссылка на объект -- он живет. null -- это значение, такое же, как function() {...}

Так почему gc должен высвобождать ресурсы?

etc 15.05.2006 21:12

Antares, ок. Но есть утверждение, что после delete создание нового onEnterFrame займёт времени больше, чем присваивание другого значения...

Homo Sapiens 15.05.2006 22:47

null это значение??? null - это null. 0 - значение

iNils 15.05.2006 23:25

Цитата:

Сообщение от __etc
Antares, ок. Но есть утверждение, что после delete создание нового onEnterFrame займёт времени больше, чем присваивание другого значения...

Все запускалось по 5 раз в flash mx.
Присваивание другого значения:
Код:

f = function () {
        delete this.onEnterFrame;
};
for (i = 0; i < 2000; i++) {
        this.createEmptyMovieClip ("mc" + i, i);
        this["mc" + i].onEnterFrame = null;
}
t1 = getTimer ();
for (i = 0; i < 2000; i++) {
        this["mc" + i].onEnterFrame = f;
}
t2 = getTimer ();
trace (t2 - t1);

Получил: 142, 141, 143, 149, 142

создаем новый onEnterFrame:
Код:

f = function () {
        delete this.onEnterFrame;
};
for (i = 0; i < 2000; i++) {
        this.createEmptyMovieClip ("mc" + i, i);
}
t1 = getTimer ();
for (i = 0; i < 2000; i++) {
        this["mc" + i].onEnterFrame = f;
}
t2 = getTimer ();
trace (t2 - t1);

Получил: 153, 155, 154, 155, 153.

Homo Sapiens 15.05.2006 23:31

Код:

var allObjects:Array = new Array();

function CreateObject():Object
{
        var obj:Object = new Object();
        for(var i = 0; i < 100; i++)
        {
                obj["prop" + i] = new Object();
                obj["prop" + i].str = i + ". this is string number " + i;
                obj["prop" + i].numb = Math.round(Math.random() * 0xFFFFF);
        }
       
        obj.Clear = function():Void
        {
                for(var i = 0; i < 100; i++)
                {
                        this["prop" + i].str = null;
                        this["prop" + i].numb = null;
                }
        }
        return obj;
}

function AddObjects():Void
{
        var i = 0, max = Math.round(Math.random() * 0xFF);
        for(; i < max; i++)
        {
                allObjects.push(CreateObject());
        }
}

var pos = 0;
function ClearProperties():Void
{
        alert("Clear");
        var max = pos + 0xFFFFF;
        //var max = pos + 0xFFF;
        for(; pos < max; pos++)
        {
                if(pos >= allObjects.length)
                {
                        pos = 0;
                        max = 0;
                }
                allObjects[pos] = null;
                          //delete allObjects[pos];
        }
}

function StopAll():Void
{
        clearInterval(interAdd);
        clearInterval(interClear);
        clearInterval(interStop);
        clearInterval(interUpdate);
}

function Update():Void
{
        info.text = "Количество элементов: " + allObjects.length;
        info.text += "\nПозиция: " + pos;
}

var interAdd = setInterval(AddObjects, 1000);
var interClear = setInterval(ClearProperties, 10000);
var interStop = setInterval(StopAll, 15 * 60000);
var interUpdate = setInterval(Update, 2000);

Запускаем, обращаем внимание на прирост памяти.

Потом раскоментируем меняем местами закомментированные строки. Особенно хорошо видно при больших значениях (> 10000).

P.S. Текстовое поле info создаём ручками :)

Homo Sapiens 15.05.2006 23:36

Пример достаточно нагляден. delete работает на самом деле ощутимо быстрее чем присвоение null. Но присвоение null тоже работает...

Homo Sapiens 15.05.2006 23:51

Код:

var allObjects:Array = new Array();

function CreateObject():Object
{
        var obj:Object = new Object();
        for(var i = 0; i < 100; i++)
        {
                obj["prop" + i] = new Object();
                obj["prop" + i].str = i + ". this is string number " + i;
                obj["prop" + i].numb = Math.round(Math.random() * 0xFFFFF);
        }
       
        obj.Clear = function():Void
        {
                for(var i = 0; i < 100; i++)
                {
                        this["prop" + i].str = null;
                        this["prop" + i].numb = null;
                }
        }
        return obj;
}

function AddObjects():Void
{
        var i = 0, max = Math.round(Math.random() * 0xFF);
        for(; i < max; i++)
        {
                allObjects.push(CreateObject());
        }
}

var pos = 0;
function ClearProperties():Void
{
        alert("Clear");
        var max = pos + 0xFFFFF;
        for(; pos < max; pos++)
        {
                if(pos >= allObjects.length)
                {
                        pos = 0;
                        max = 0;
                }
                //allObjects[pos] = null;
                delete allObjects[pos];
        }
}

function StopAll():Void
{
        clearInterval(interAdd);
        clearInterval(interClear);
        clearInterval(interStop);
        clearInterval(interUpdate);
       
        info.text += "\nКонец работы, заполнение массива";
       
        var len = allObjects.length;
        for(var i = 0; i < len; i++)
        {
                allObjects[i] = CreateObject();
        }
}

function Update():Void
{
        info.text = "Количество элементов: " + allObjects.length;
        info.text += "\nПозиция: " + pos;
}

var interAdd = setInterval(AddObjects, 1000);
var interClear = setInterval(ClearProperties, 10000);
var interStop = setInterval(StopAll, 3 * 60000);
var interUpdate = setInterval(Update, 2000);

Ещё один тестик, не рекомендую если меньше гига оперативки. Кстати, все тесты исполнялись с приоритетом Realtime

Madasan 15.05.2006 23:52

Цитата:

Сообщение от Homo Sapiens
null это значение??? null - это null. 0 - значение

null - это значение, которое указывает на отсутствие этого самого значения. То есть тут получается как бы отсутсвие значения - это тоже значение, то есть наша переменная значения как такового не имеет, но все таки она не undefined !

Homo Sapiens 15.05.2006 23:55

Код:

var allObjects:Array = new Array();

var testObj:Object = new Object();
testObj.prop = 1;

var realVar:Number = 1;

function CreateObject():Object
{
        var obj:Object = new Object();
        for(var i = 0; i < 100; i++)
        {
                obj["prop" + i] = new Object();
                obj["prop" + i].str = i + ". this is string number " + i;
                obj["prop" + i].numb = Math.round(Math.random() * 0xFFFFF);
        }
       
        obj.Clear = function():Void
        {
                for(var i = 0; i < 100; i++)
                {
                        this["prop" + i].str = null;
                        this["prop" + i].numb = null;
                }
        }
        return obj;
}

function AddObjects():Void
{
        var i = 0, max = Math.round(Math.random() * 0xFF);
        for(; i < max; i++)
        {
                allObjects.push(CreateObject());
        }
}

var pos = 0;
function ClearProperties():Void
{
        alert("Clear");
        var max = pos + 0xFFFFF;
        for(; pos < max; pos++)
        {
                if(pos >= allObjects.length)
                {
                        pos = 0;
                        max = 0;
                }
                //allObjects[pos] = null;
                //delete allObjects[pos];
                //allObjects[pos] = testObj;
                allObjects[pos] = realVar;
        }
}

function StopAll():Void
{
        clearInterval(interAdd);
        clearInterval(interClear);
        clearInterval(interStop);
        clearInterval(interUpdate);
       
        info.text += "\nКонец работы, заполнение массива";
       
        var len = allObjects.length;
        for(var i = 0; i < len; i++)
        {
                allObjects[i] = CreateObject();
        }
}

function Update():Void
{
        info.text = "Количество элементов: " + allObjects.length;
        info.text += "\nПозиция: " + pos;
}

var interAdd = setInterval(AddObjects, 1000);
var interClear = setInterval(ClearProperties, 10000);
var interStop = setInterval(StopAll, 3 * 60000);
var interUpdate = setInterval(Update, 2000);

Ну и самый последний вариант, что называется для полноты картины...

Homo Sapiens 15.05.2006 23:58

undefined во Flash сделано исключительно для удобства дизайнеров, чтобы им не напрягаться. Буквально это значит "не определена". В нормальных языках программирования, попытка использовать неопределённую переменную приводит к ошибке компиляции. И как правило, эти языки в принципе не дают объявить неинициализированную ссылочную переменную, требуя присвоить null, если пока нельзя определить конкретную цель для указателя.


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

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.