Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
afterlag.do(callback) будет ведь выполнен только раз?.. То есть, если у меня динамический контент, то после конца загрузки и вставки контента на страницу я должен создать новый инстанс afterlag, верно?afterlag.on('begin', function() {
console.log('начались лаги, ждем...');
});
afterlag.on('end', function() {
console.log('лаги прекратились, исправляем...');
});
Это на случай динамического контента и тому подобного. И да, возможно, лучше было бы использовать requestAnimationFrame? Если кадры пропускаются — значит, анимации точно будет плохо. А если не пропускаются — может, не все так печально?on('begin', ...) имело смысл, нужно оставлять афтерлаг все время включенным. Афтерлаг почти в состоянии сам вызвать лаги, я не хотел бы оставлять включенным всё время работы сайта. Ведь при создании нового инстанса и так можно сказать, что лаги начались, ведь мы их ожидаем. А даже если их нет, это скорее всего никак не повлияет на наши действия. Я стремился сделать плагин максимально казуальным, и в идеале подобрать такие настройки, чтобы никому не пришлось с ними играться.on('end', ...) сейчас работает как do(...).requestAnimationFrame лучше подходит для анимаций, т.к. ограничен фреймрейтом и вызывается перед тем, как браузер будет перерисовывать кадр. Все или почти все анимации используют эту функцию, поэтому планировщик браузера может вместо кучи событий таймеров обработать только одно. Поэтому, если лагает эта функция, то лагают и анимации. Если эта функция не лагает, анимации работают плавно. А если лагает setTimeout, это не всегда имеет негативный эффект на анимациях — возможно как раз, что браузер только анимациями и занят.coffee-script/register.@constructor.defaults не самая хорошая конструкция. Может, лучше использовать просто @defaults?for key of first_object — почему не for own key of first_object?new Date().getTime() можно заменить на do Date.nowfn = self; self = @ можно заменить на [fn, self] = [self, @]@constructor.defaults или Afterlag.defaults# Сейчас в коде так:
class Afterlag
@defaults:
delay: 100
# ...
# Если бы было вот так, нужно было бы использовать @defaults.
class Afterlag
defaults:
delay: 100
# ...
Date.new работает с только с девятого IE. А «requestAnimationFrame», кстати, с десятого. С одной стороны черт бы сними, но все же. А интервалы любой бразуер тянет. Но я все равно покапаю в сторону «requestAnimationFrame».window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(){
window.setTimeout(callback, 1000 / 60);
};
})();
@defaults: ...? Если вы посмотрите билд при defaults: ..., там будет Afterlag.prototype.defaults, что вполне себе так же хорошо и здорово, как и Afterlag.defaults, но при обращении к первому варианту не нужно прибегать к дереференсу конструктора. Да, кстати, Afterlag.prototype.defaults еще можно писать, как Afterlag::defaults.[a, b, ..., c] = [1, 2, 3, 4, 5, 6, 7] # a == 1, b == 2, c == 7
{a, b, c} = {a: 10, foo: 99, b: 30} # a == 10, b == 30, c == undefined
{a: foo, b: bar} = {a: 265, b: 42} # foo == 265, bar == 42
{@foo, @bar, @quux} = options # @foo == options.foo, @bar == options.bar, @quux == options.quux
Afterlag.defaults.iterations = 5. И потом при создании новых объектов мне не придется каждый раз указывать в настройках, что я хочу 5 итераций. Они возьмутся из нового дефолтного значения.function Class(foo) {
if (foo != null) {
this.foo = foo;
}
}
Class.prototype.foo = 42;
a = new Class();
b = new Class(100);
console.log('a ->', a.foo); // 42
console.log('b ->', b.foo); // 100
console.log();
Class.prototype.foo = 666;
a2 = new Class();
b2 = new Class(100);
console.log('a ->', a.foo); // 666
console.log('b ->', b.foo); // 100
console.log('a2 ->', a2.foo); // 666
console.log('b2 ->', b2.foo); // 100
console.log();class Class
foo: 42
constructor: (foo) ->
@foo = foo if foo?
a = new Class
b = new Class 100
console.log 'a ->', a.foo # 42
console.log 'b ->', b.foo # 100
do console.log
Class::foo = 666;
a2 = new Class
b2 = new Class 100
console.log 'a ->', a.foo # 666
console.log 'b ->', b.foo # 100
console.log 'a2 ->', a2.foo # 666
console.log 'b2 ->', b2.foo # 100
do console.logfoo, и которые не переприсвоили его в свой контекст. Если обновление уже существующих объектов нежелательно, то можно написать вот так:function Class(foo) {
this.foo = (foo == null) ? this.foo : foo;
}class Class
foo: 42
constructor: (@foo = @foo) ->defaults: ... заключается в том, что мне в коде самого плагина не придется писать @constructor.defaults. А в остальном все в порядке?@constructor.defaults в коде плагина использую только один раз. Зато все пользователи плагина, если захотят изменить дефолтное значение, будут писать Afterlag.defaults.iterations = ..., а в вашем случае придется писать Afterlag.prototype.defaults.iterations = .... Это длиннее, и выглядит не так интуитивно понятно.Я конструкцию constructor.defaults в коде плагина использую только один разТут, скорее, речь о том, что вы используете неявно определенные свойства, т.е. это эдакие протекающие абстракции. Ведь
constructor, к которому вы обращаетесь, и constructor в объявлении класса — это вообще разные вещи, и совпадают у них названия абсолютно случайно. CoffeeScript мог назвать свой конструктор ctor, или так же, как имя класса, или вообще считать конструктором первую определенную в классе безымянную фукнцию (как в LiveScript — рекомендую попробовать). Тогда как @constructor ссылается на свойство конструктора, которое назначается рантаймом автоматически после инстанцирования объекта:function Class() { }
var a = new Class;
console.log(a.constructor); // [Function: Class]Спасибо, что разъяснили про наследование. И примеры у вас замечательные. И комментарии интересные.Сарказм? :) Учитывая, что комментарии просто максимально информативны —
# 666, # 100 и # 42.@constructor.default я понимал, что он не связан тем конструктором, который в объявлении класса. Собственно по-этому я его в коде верно и использовал. Если бы вместо @constructor.defaults я использовал Afterlag.defaults никаких неявно определенных свойств и протекающих абстракций бы не было. Но мне не хотелось внутри класса обращаться к классу по имени, я хотел обратиться через какой-то универсальный указатель. Сейчас посмотрел документацию к кофескрипту, там, и вправду, нигде не говорят, что так можно делать. Значит я этот способ где-то в другом месте вычитал. Может и стоит заменить это на Afterlag.defaults, но мне по прежнему не хочется к классу обращаться по имени внутри этого же класса.class MyClass
foo: 42
bar: null
buzz: 'meow'
quux: 3.14
constructor: (opts) ->
do => @[key] = value for own key, value of opts # merge options
# do something useful...
toString: -> "foo: #{@foo}, bar: #{@bar}, buzz: #{@buzz}, quux: #{@quux}"
a = new MyClass
console.log "#{a}" # foo: 42, bar: null, buzz: meow, quux: 3.14
b = new MyClass foo: 666
console.log "#{b}" # foo: 666, bar: null, buzz: meow, quux: 3.14
c = new MyClass foo: null
console.log "#{c}" # foo: null, bar: null, buzz: meow, quux: 3.14MyClass::bar = 'okay, new bar field'.Afterlag.prototype.defaults.iterations = 5. Слишком длинная строка.1. Анимация будет более плавной, так как браузер может оптимизировать её
2. Анимация в неактивной вкладке будет приостановлена, позволяя процессору отдохнуть
3. Более энергоэкономна.
Анимация против лагов, или лучшая битва та, которой не было