Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > JavaScript: Общие вопросы > Как отложить вызов функции на 1 сек


Автор: DEER 25.7.2007, 11:31
Народ, привет.
Не подскажете как можно начать выполнять функцию, после того как пользователь ввел какой то текст в input type=’text’ и если длина введенной строки > 3 символов?
Под «после того как пользователь ввел какой то текст» я подразумеваю, что он сделал паузу в набирании > 1 секунды, например

То есть как сдесь на форуме, вводишь название темы - страница джет какое то время, а потом ищет похожие темы

Пробовал так

Код

onkeyup=’setInterval(“myFunc”, 1000)’


но результат не такой как я ожидал, да и this.value, как я понял, ещё не содержит введенного символа

Автор: smartov 25.7.2007, 11:45
Все верно. Нужно использовать setТimeout

Автор: SelenIT 25.7.2007, 17:48
Цитата(DEER @  25.7.2007,  11:31 Найти цитируемый пост)
this.value, как я понял, ещё не содержит введенного символа

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

onkeyup="if(this.t)clearTimeout(this.t); this.t=setTimeout((function(argument) { return function() { alert(argument);} })(this.value), 1000)"


Автор: smartov 25.7.2007, 18:03
SelenIT, вопрос задавал не я, но я ставлю плюс, потому что долго не мог найти как передавать инлайном параметры в лямда-функции smile

Автор: Zeroglif 25.7.2007, 19:36
Код

setTimeout('func(\''+this.value+'\')',1000)


 smile 

Автор: SelenIT 25.7.2007, 20:03
Zeroglif, это даже неспортивно как-то... smile 

Автор: AKS 26.7.2007, 07:16
Цитата(SelenIT @  25.7.2007,  20:03 Найти цитируемый пост)
даже неспортивно как-то...

Куда деваться - мы же с ним в "разных весовых категориях" smile
А по-теме, кстати, вот что:
Код

<input type='text' onkeyup='clearTimeout(this.t); this.t = setTimeout(myFunc, 1000, this)' />

SelenIT, дополнительные параметры ведь уже давно поддерживают и FF, и Opera (любимая нежно ;) ). Причем эта "фича" уже не новая - точно не знаю, с какого времени, но у меня FF 0.8 (2004 г) "узнает это дело" (короче говоря, "фича" с тех времен, когда я не знал, что такое "хтмл" ;) ).
Что я хочу сказать - удобно ведь очень! Передал this и делай в myFunc (где он будет первым аргументом) с этим this все, что хочешь!
Чтобы это работало в IE, можно написать доп. расширение. На форуме Xpoint я писал, но оставили без комментариев. Попробую здесь, в здешней компании обсудить вот такое расширение для IE:
Код

function windowXpander(aMethod) {
    var original = window[aMethod];
    window[aMethod] = function (aFunc, aDelay) {
        var args = [],
            len = arguments.length,
            func;
        if (len > 2) {
            while (len-- > 2) {
                args[len - 2] = arguments[len];
            }
            func = function () {
                return aFunc.apply(null, args); // вот здесь еще бы научиться без apply...
            }
        }
        return original(func || aFunc, aDelay);
    }
}

if (window.execScript) {
    windowXpander('setTimeout');
    windowXpander('setInterval');
}


В результате - функция myFunc из аттрибута onkeyup:
Код

function myFunc(aThis) {
    alert(aThis.value);
}

отработает и в IE...

Автор: DEER 26.7.2007, 09:28
Народ всем спасибо.
Я сам сделал, залез выложить а тут такое )
мой вариант
Код

function time_kdoun() {
    flag = false;
}
function time_kup(DivId, tbId, hiddenId, minCount) {
    flag = true;
    clearInterval(interval);
    interval = setInterval('check_flag("'+DivId+'", "'+tbId+'", "'+hiddenId+'", '+minCount+')', 1500);
}

function check_flag(DivId, tbId, hiddenId, minCount) {
    clearInterval(interval);
    if(flag) {
        findCompanies(DivId, tbId, hiddenId, minCount);
    }
}

Код

<input type="text" name="companySearcher" id="companySearcher" size="20" maxlength="50" style="width:300" onkeyup="time_kup('ajaxDiv', 'companySearcher', 'model.companyId', 3)" onkeydown="time_kdoun()"/>

Автор: AKS 26.7.2007, 10:13
Цитата(DEER @  26.7.2007,  09:28 Найти цитируемый пост)
Я сам сделал...

А предложенный мной вариант испытать не желаете? Давайте "рискнем"! ;)
Получится как-нибудь так:
Код

<input type="text" onkeyup="clearTimeout(findCompanies.id);
 findCompanies.id = setTimeout(findCompanies, 1000, 'ajaxDiv', this, 'model.companyId', 3)"  />

Только вместо id этого поля в функцию findCompanies будет передана ссылка непосредственно на это поле (не надо будет писать document.getElementById или типа того). И вспомогательных функций time_kdoun/time_kup не понадобится...

Автор: Zeroglif 26.7.2007, 10:24
Цитата(AKS @  26.7.2007,  07:16 Найти цитируемый пост)
Что я хочу сказать - удобно ведь очень!


- а как быть со строкой первым аргументом?
- а как быть с синтаксисом setTimeout в IE, не страшно?

Автор: AKS 26.7.2007, 10:53
Zeroglif
1. Как быть со строкой первым аргументом?
Думаю, что здесь может помочь знание синтаксиса - http://developer.mozilla.org/en/docs/DOM:window.setTimeout/http://developer.mozilla.org/en/docs/DOM:window.setInterval.
2. Как быть с синтаксисом setTimeout в IE, не страшно?
"Волков бояться - в лес не ходить". ;) Я как-раз для этого и предложил взглянуть на windowXpander, чтобы разобраться и потом уже ничего не бояться. Очень надеюсь на Вас, в частности в случае с apply ("старая гвардия" должна знать, как обойтись без него - ведь как-то обходились до третьего издания, или до второго... когда он там появился).

Автор: Zeroglif 26.7.2007, 11:40
Цитата(AKS @  26.7.2007,  10:53 Найти цитируемый пост)
Думаю, что здесь может помочь знание синтаксиса

То есть отказаться от использования строк вообще... или всё-таки проще доделать функцию? 

Цитата(AKS @  26.7.2007,  10:53 Найти цитируемый пост)
чтобы разобраться и потом уже ничего не бояться

IE описал свой синтаксис, мы выходим за его рамки, остаётся только верить в лучшее...  smile

Цитата(AKS @  26.7.2007,  10:53 Найти цитируемый пост)
старая гвардия

Не про меня.

Цитата(AKS @  26.7.2007,  10:53 Найти цитируемый пост)
как обойтись без него

Собрать из массива будущие аргументы в строку, потом вызов через eval... если же предполагать, что число аргументов всё-таки имеет разумный предел (3-5), то проще проверять по switch-case длину массива и вперёд...

Автор: AKS 26.7.2007, 12:14
Цитата(Zeroglif)

Отказаться от использования строк вообще.

Нет, я себе это представил следующим образом. Раз известен синтаксис, который в случае со строкой в первом агрументе не предполагает использования экстра-параметров, то и нечего на них расчитывать. Т.е. все просто: хочешь строку - забудь про доп. параметры.
Цитата(Zeroglif)

IE описал свой синтаксис.

Ну мне показалось, что расширение довольно "безобидное", т.е. ничего вроде бы не "ломает".
Цитата(Zeroglif)

Не про меня.

Да неужели? smile
Цитата(Zeroglif)

Вызов через eval.

У меня сегодня чего-то "замкнуло" в этой, самой, как ее там называют - ее еще почесать можно... тьфу - в голове. smile Знаю прекрасно, как делается эмуляция apply/call, а вот как это дело портировать в саму функцию? Ну не могу чего-то сегодня и все. Чуть позже попробую со второй попытки...

Автор: Zeroglif 26.7.2007, 12:37
Цитата(AKS @  26.7.2007,  12:14 Найти цитируемый пост)
Т.е. все просто: хочешь строку - забудь про доп. параметры.

Хех... а код-то вы похоже исправили, а я-то копипастнул первоначальный, тот, где if (len > 1)...  smile 
Цитата(AKS @  26.7.2007,  12:14 Найти цитируемый пост)
ничего вроде бы не "ломает".

определяюшая фраза - "вроде бы"... 

Автор: AKS 26.7.2007, 13:00
Цитата(Zeroglif @  26.7.2007,  12:37 Найти цитируемый пост)
а код-то вы похоже исправили

Да, исправил - Вам СПАСИБО!!!
Цитата(Zeroglif @  26.7.2007,  12:37 Найти цитируемый пост)
определяюшая фраза - "вроде бы"

Ну а еще подсказочку можно? Звонок другу или чего там еще бывает? smile


Автор: Zeroglif 26.7.2007, 13:46
AKS

ОК... я могу легко снять брюзжание по поводу непредсказуемости IE, не могу сформулировать точно, поэтому снимаю. Если формулировать в стиле бла-бла-бла, то хостовые методы живут своей жизнью плюс у IE судя по всему оригинальная реализация глобального объекта (он как бы двоится), отсюда возможные сюрпризы при присваивании ссылки на эти методы переменным или их замене на что-то своё. Несмотря на это стоит заметить, что не вы один пытаетесь сэмулировать setTimeout, есть http://webreflection.blogspot.com/2007/06/simple-settimeout-setinterval-extra.html и http://ecmascript.stchur.com/2006/06/07/settimeout-revisited/... это хорошо, значит, они тоже тестировали и тоже пришли к позитивному выводу, это радует...  smile 

Автор: smartov 26.7.2007, 14:07
Я не совсем понимаю зачем вы устроили споры по поводу дороговизны реализации setTimeout для веб-девелоперов всех стран, если есть кросбраузерный вариант, который уже давно http://forum.vingrad.ru/index.php?showtopic=165006&view=findpost&p=1206881.

Автор: Zeroglif 26.7.2007, 14:25
smartov

создавать 2 дополнительных функции и делать 1 дополнительный вызов только ради того, чтобы удержать в руках ссылку на текущий объект - это ненормально. Можно, конечно, обойтись и 1-ой функцией, но это тоже будет слишком жирно для такой простой задачи. Отсюда движки, осознающие эту ненормальность, предлагают свои правильные нормальные решения и вводят дополнительные аргументы. Чтоб нам было удобно. 

AKS предлагает эмуляцию такого "правильного решения" для IE. Чтоб нам было удобно. Это никак не отменяет пользы замыканий (вариант SelenIT), это дорога в ту же сторону, никто не спорит, просто трём'c...

Автор: smartov 26.7.2007, 14:27
Zeroglif, ааа... ясно

Просто как по мне ничего такого особенно в провозглашении анонимной функции и ее вызове нету. Любо явист вообще скажет что это в порядке вещей.

Автор: AKS 26.7.2007, 14:30
Цитата(Zeroglif @  26.7.2007,  13:46 Найти цитируемый пост)
я могу легко снять брюзжание

Ну-у-у, какое же это "брюзжание". Сейчас я Вас буду убеждать, что ничего подобного тут нет. Вот чего далеко ходить - испытал я "ихние" варианты, а они не работают со строкой в первом аргументе. А чья заслуга, что вариант из этой темы со строкой работает? Не буду показывать пальцем... ;)
Цитата(Zeroglif @  26.7.2007,  13:46 Найти цитируемый пост)
...значит, они тоже тестировали и тоже пришли к позитивному выводу

Они, безусловно, молодцы - отличные практики. Очень-очень много полезного пишут. Но кроме того, что я уже отметил, они вот, между нами говоря, мои комменты не-е-е публикуют!!! 
Вчера по вашей ссылке написал Andrea, что он чего там попутал в своей $extend:
Код

// p="prototype"
f[p]=b[p]; // зачем это, если сразу переопределяет?
f[p]=new f;

А Stev'y тоже писал, что null - 15 = -15 - это норма поведения (ECMAScript 9.3) - тоже не захотел публиковать критику. 
Но это я так, к слову - я на них ничуть не обижаюсь, т.к. у них тоже учусь. Спасибо им.

Возвращаясь к эмуляции для IE нужно заметить, что подавляющее кол-во программ именно так и написаны программерами - НА НАШ СТРАХ И РИСК. Так что одной эмуляцией больше, одной меньше - ну подумаешь у кого-нибудь чего-нибудь "слетит с катушек"... smile

Автор: Zeroglif 26.7.2007, 15:13
Цитата(smartov @  26.7.2007,  14:27 Найти цитируемый пост)
Просто как по мне ничего такого особенно в провозглашении анонимной функции и ее вызове нету. Любо явист вообще скажет что это в порядке вещей.

Согласен. Анонимная функция сама по себе может и в порядке вещей, но использовать её не из любви к искусству, а почём зря или вынужденно - это имхо беспорядок.

Код

var x = 1;

// или

var x = function (a) { return function () { return a; }; }(1)();

// ?

Автор: AKS 26.7.2007, 16:57
Zeroglif, я написал вариант без apply. Сделал, кстати, еще и условие "пожестче":
Код

if (typeof (aFunc) === 'function' && len > 2) // чтобы строка не попала

Но ведь конструкция с eval помедленней получается! Вот тест:
Код

function F(aFunc, aArray) {
    var params = [],
        len = aArray.length;
    while (len--) {
        params[len] = 'aArray[' + len + ']';
    };
    return eval('aFunc(' + params + ')');
};

/*
function F(aFunc, aArray) {
    return aFunc.apply(this, aArray);
};
*/

var t = new Date,
    i = 100000;

while (i--) {
    F(function (a, b, c, d, e, f) {
        return [a, b, c, d, e, f]; },
      [1, 2, 3, 4, 5, 6]);
}

alert((new Date) - t);

Спрашиваю вашего мнения, т.к. именно Вы всегда отмечаете, что apply/call - это вещи, которые далеко не везде "известны".

Автор: Zeroglif 26.7.2007, 19:22
Цитата(AKS @  26.7.2007,  16:57 Найти цитируемый пост)
пожестче

Это правильно.

Цитата(AKS @  26.7.2007,  16:57 Найти цитируемый пост)
конструкция с eval помедленней получается

Игра-то ваша, вы же хотите уйти от apply и в то же время поддержать неопределённое число аргументов, куда деваться-то... имхо трёх допаргументов хватит за глаза.

Автор: AKS 26.7.2007, 20:33
Цитата(Zeroglif @  26.7.2007,  19:22 Найти цитируемый пост)
...вы же хотите уйти от apply

Не по своей воле. smile Хотя не сложно сделать "ветвистый" вариант - и с apply, и с eval (пусть так и будет).
Цитата(Zeroglif @  26.7.2007,  19:22 Найти цитируемый пост)
Это правильно.

Тут по-поводу "жесткости" еще вопросы появляются. Вот так:
Код

window.setInterval('window.status += 2', 1000, 1);

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


Автор: Zeroglif 27.7.2007, 00:36
Цитата(AKS @  26.7.2007,  20:33 Найти цитируемый пост)
может это только у меня не работает

У меня тоже не работает. Равно как и игра с другими свойствами хоста, например, document.title+=2, что-то IE не нравится, или давай ему третьим аргументом язык, или упс...

Цитата(Zeroglif @  26.7.2007,  13:46 Найти цитируемый пост)
хостовые методы живут своей жизнью


Автор: AKS 27.7.2007, 09:03
Цитата(Zeroglif @  27.7.2007,  00:36 Найти цитируемый пост)
...давай ему третьим аргументом язык

Еще раз спасибо! Ситуация проясняется. Все верно - по умолчанию 'jscript', а тут вдруг указал я ему черт знает что - конечно не будет работать, ведь строку на таком языке ( 1 ) он разобрать не может...

P.S.
Вы, наверно, миллионер (если исчислять в "спасибо")? smile

Автор: AKS 27.7.2007, 10:21
Ну чтож, пока вот такая штуковина получилась - надеюсь, что больше никаких "аномалий" не выявится (главное - придумал имя крутое smile ):
Код

function XpandDelaySetter(aMethod) {
    var fnOriginal = window[aMethod],
        bNative = /\[native\scode\]/.test(fnOriginal);
    if (!bNative) {
        return false;
    };
    window[aMethod] = function (aFunc, aDelay, aLang) {
        var oArgs = arguments,
            iLen = oArgs.length,
            iIter = 2,
            vCodeType = typeof (aFunc),
            bCheckLang = iLen === 3 && 
                /^(jscript|javascript|vbscript)$/i.test(aLang),
            bHostMeth = vCodeType == 'object' &&
                /function/.test(aFunc),
            bEval = !Function.prototype.apply || bHostMeth,
            vParams = bEval ? '' : [],
            sDiv = '',
            fnCallBack;
        if (vCodeType == 'string' || bCheckLang) {
            fnCallBack = aFunc;
        } else if ((vCodeType == 'function' || bHostMeth) &&
                iLen > iIter) {
            for (; iIter < iLen; iIter++) {
                bEval ? vParams += sDiv + 'oArgs[' + iIter + ']'
                      : vParams[vParams.length] = oArgs[iIter];
                sDiv = ', ';
            };
            fnCallBack = function () {
                return (bEval
                       ? eval('aFunc(' + vParams + ')')
                       : aFunc.apply(this, vParams));
            };
        };
        return fnOriginal(fnCallBack || aFunc, aDelay, aLang);
    };
};

Автор: smartov 27.7.2007, 10:32
Оригинально, но велосипед еще тот  smile 

Автор: AKS 27.7.2007, 10:46
Цитата(smartov @  27.7.2007,  10:32 Найти цитируемый пост)
...велосипед еще тот

Т.е. это уже где-то кто-написал? Чтож Вы сразу не сказали - я бы время зря не тратил. :(

Автор: Diesel Draft 27.7.2007, 10:50
settimeout();

Автор: Zeroglif 27.7.2007, 11:36
AKS

Если language пришёл третьим аргументом его бы надо пропустить в родной таймаут. Вместо !aFunc.apply лучше !Function.prototype.apply. Проверка на [native code] мне кажется лишней/непредсказуемой, может всё-таки обезопасить себя не переопределением родного/чужого setTimeout-а, а созданием своего (отдельно лежащего) метода (как у stchur-а) на свой объект. Строгое равенство при сравнении с typeof aFunc - масло масляное. Не хотите проверить на неравенство сo 'string', чем равенство с 'function' , у IE некоторые методы типа 'object', да и в разных браузерах может быть по разному. Где итерация и где return из func я бы записал всё в одну строку тернарным..., легче будет читать...

Ещё, чуть не забыл, аргументы для eval лучше бы собрать в строку, !!!не стоит полагаться на массив.

AKS, +1

Добавлено @ 11:42
Цитата(Diesel Draft @  27.7.2007,  10:50 Найти цитируемый пост)
settimeout();

Лучше SETtimeOUT();  smile 

Автор: AKS 27.7.2007, 12:10
О-о-о, спасибО!
Цитата(Zeroglif @  27.7.2007,  11:36 Найти цитируемый пост)
Если language пришёл третьим аргументом его бы надо пропустить в родной таймаут.

Точно, так и надо! Сделаю!

Цитата(Zeroglif @  27.7.2007,  11:36 Найти цитируемый пост)
Вместо !aFunc.apply лучше !Function.prototype.apply.

А вот это не понял - чем лучше?

Цитата(Zeroglif @  27.7.2007,  11:36 Найти цитируемый пост)
Проверка на [native code]...

Т.е. где-нибудь может и по-другому выглядеть нативный body? Вот хотелось бы, конечно, не так, как у Стива. "Заманчивей" выглядит так, как сейчас, хотя если делать по-серьезному, типа безопасней ("по-взрослому"), то надо так, как Вы пишите.

Цитата(Zeroglif @  27.7.2007,  11:36 Найти цитируемый пост)
...масло масляное

Сделаю "постным". smile

Цитата(Zeroglif @  27.7.2007,  11:36 Найти цитируемый пост)
Не хотите проверить на неравенство сo 'string'...

Уже хочу - переделаю.

Цитата(Zeroglif @  27.7.2007,  11:36 Найти цитируемый пост)
я бы записал всё в одну строку тернарным...

Ну и я тогда также сделаю.

Цитата(Zeroglif)

...!!!не стоит полагаться на массив

Ух, а что не так с массивом?

P.S. 
Чуть позже отредактирую функцию там, где она уже есть (новых сообщений делать не буду).

Автор: AKS 27.7.2007, 12:48
Zeroglif, надоело Вам тут уже в одной теме наверно, но я все же еще побеспокою, поскольку вопросец назрел серьезный. 
Вы говорите "у IE некоторые методы типа 'object'", и вместо равенства с 'function' выбрать 'string'. А как же тогда быть, если кто-нибудь сунет что-то без [[Call]]? Поместить вызов в try/catch?

P.S. 
А может на предмет "передана ли исполняемая процедура?" проверять как-нибудь по такому принципу:
Код

/function/.test(alert)

?
Да тут еще с этими 'object' выясняется, что проверка на !aFunc.apply просто необходима...
Код

window.setTimeout(alert, 1000, 'Нету ведь apply!');

Как-то так, пока:
Код

        if (typeof (aFunc) == 'string' || check) {
            func = aFunc;
        } else if ((typeof (aFunc) == 'function' ||
                typeof (aFunc) == 'object' &&
                /function/.test(aFunc)) && len > iter)

Автор: Zeroglif 27.7.2007, 13:35
Цитата(AKS @  27.7.2007,  12:48 Найти цитируемый пост)
Поместить вызов в try/catch?

Зачем? Пусть ошибки лезут. Не суй в другой раз.  smile 

Цитата(AKS @  27.7.2007,  12:10 Найти цитируемый пост)
чем лучше?

aFunc имеет полное право тащить на себе левое свойство applyFunction.prototype - тоже, но там скорее всего или не будет ничего вообще, или будет уже готовая эмуляция.

Цитата(AKS @  27.7.2007,  12:10 Найти цитируемый пост)
что не так с массивом?

toString может быть некачественно реализован или переопределён.

Автор: AKS 27.7.2007, 13:42
Так, ясненько! Смотрите, как прикольно получается:
Код

window.setTimeout(window.open, 1000, 'about:blank', '', 'width=300,height=300');

!!! smile
Как же "присобачить" к возвратному значению ссылку на новое окно? В принципе, вернуть-то можно что угодно. smile Надо ли? Народ "засмущается" - вместо ссылки на id таймера вылезет у меня какой-нибудь объект, обвешанный всякими returned value. smile

Добавлено @ 13:47
Цитата(Zeroglif @  27.7.2007,  13:35 Найти цитируемый пост)
aFunc имеет полное право тащить на себе левое свойство apply

Так, раз такое дело, то тогда так, наверно:
Код

 bool = !(Function.prototype.apply && typeof (aFunc) == 'function')
// или Function.apply - чтоб короче


Автор: Zeroglif 27.7.2007, 13:56
Цитата(AKS @  27.7.2007,  13:42 Найти цитируемый пост)
Как же "присобачить" к возвратному значению ссылку на новое окно?

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

Автор: smartov 27.7.2007, 14:15
Цитата(Zeroglif @  27.7.2007,  12:56 Найти цитируемый пост)
запускай хостовый метод так, чтобы поймать всё, что нужно (через свою функцию). 

Отож. Балакали балакали...

Автор: AKS 27.7.2007, 14:16
Цитата(Zeroglif @  27.7.2007,  13:56 Найти цитируемый пост)
И не нужно.

Ну и хорошо - ничего лишнего, здоровая умеренность во всем! smile
Вот как же быть с проверкой [native code] - хочется ведь получить родной метод или прервать выполнение кода...

Отредактировал функцию на 2-ой стр. (27.7.2007, 18:39).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)