.setTimeout()
附加使用, .setInterval()
to .onmousedown
, .onmouseup
,钩子的计时器函数怎么样.onmouseout
,你尝试过这种方法吗?
或者试试我用于类似任务的准备就绪功能。小提琴。
//
// #Timer
//
// if you are unfamiliar with this code construct,
// ( I think it is called 'module' pattern IIRC )
// this is base structure behind it:
//
// defines/runs/sets_context/passes_arguments of anonymous function in one go
// makes 'safe' ( private ) scope for module definition
// module assignment is performed at the top
// where it is easy to spot, rename, and shift around where needed
// 'factory' is a function that is supposed to return whatever the 'module' is
// be it a function, object, or whatever,
// and to assign it to arbitrary 'host' object,
// providing room to rename it in case of naming collisions
//
// ;(( function ( name, factory ) {
//
// // this === module's context
//
// this[name] = factory();
//
// } ).call(
//
// hostObject, // object to attach module to
// "customModuleName", // arbitrary name to use for it
// function () { // factory method that is supposed to define/return ( preferably independent ) piece of functionality
//
// // save to do whatever is required in this scope
// // without the impact on globals.
// // declare identifiers, etc.
// // whatever this function returns is assigned to context above
//
// function doStuff () {
// return Math.random() > .5;
// }
//
// var
// _api =
// {
// props : 1,
// methods : function () {
// var stuff;
// stuff = doStuff();
// return stuff;
// }
// };
//
// // ...code
//
// // and return whatever the module's goal is
// return _api;
//
// }
//
// ));
//
;(( function ( field, dfn ) {
// add 'Timer' identifier to global scope
this[field] = dfn();
} ).call(
window, // object to asign function to
"Timer", // property name to use
function () {
// helpers and
// shortcuts for use by code bellow
var undef; // === undefined
var aproto = Array.prototype;
var _ = {
// used to filter functions in timer api arguments
isfn : function ( o ) {
return typeof o == "function";
},
// is provided parameter an object
isobj : function ( o ) {
return o === Object( o );
},
// checks provided parameter,
// returns false for: null, undefined, NaN
// used to check if parameter is passed to timer methods
isvalid : function ( o ) {
return ( o != null ) && ( o === o );
},
// removes array elements that match passed arguments
// supposed to be used through .call/.apply function method:
// _.gc.call( arr, "a", "b", "c" ), etc.
// iterates array backward, '.splice-ing' it by 1 if current value
// matches one of provided arguments
// returns gc-ed array
// used by .off() method to remove scheduled function(s)
gc : function () {
// this === ( array ) target_array_to_cleanup
// provided arguments[] to remove
var togc = _.slice( arguments );
for (
var i = this.length;
--i >= 0;
( togc.indexOf( this[i] ) != -1 )
&& this.splice( i, 1 )
);
return this;
},
// empties passed array and returns it
// used by .off() method to remove scheduled functions
empty : function ( arr ) {
return ( arr.length = 0, arr );
},
// loops array
// uses native .forEach if available
// otherwise simulates the behaviour
// returns iterated array
// used by .fire() method to loop through registered function[] and
// to execute them in order
arreach : ( function () {
return ( typeof aproto.forEach == "function" )
? function ( arr, fn ) {
arr.forEach( fn );
return arr;
}
: function ( arr, fn ) {
for (
var i = 0,
l = arr.length;
i < l;
( i in arr )
&& fn.call( this, arr[i], i, arr ),
i++
);
return arr;
};
} )(),
// substitues content of array ( arr )
// with provided array's content ( arrnew )
// returns modified array ( arr )
// used by .start() method to quickly switch timer handler arguments
// if any are passed to it
arrsub : function ( arr, arrnew ) {
return ( aproto.push.apply( _.empty( arr ), arrnew ), arr );
},
// loops own properies of an object and retuns it
// used by .off() method, ant _.init() function
// to perform appropriate tasks ( object cleanup/property_assignment )
owneach : function ( obj, fn ) {
for (
var l in obj
) {
_.owns( obj, l )
&& fn.call( obj, l, obj[l] );
}
return obj;
},
// asyns a function
// returns new function based on provided one
// that will run asyncrounously
// used to async 'tick' handlers
async : function ( fn ) {
return function () {
var host = this;
var args = _.slice( arguments );
var origfn = fn;
setTimeout(
function () {
origfn.apply( host, args );
}
);
return this;
};
},
// asigns properties of an object ( propsObj )
// to provided ( obj ) object
// used in couple of places to quickly assign properties/values to objects
init : function ( obj, propsObj ) {
_.owneach(
propsObj,
function ( field, value ) {
obj[field] = value;
}
);
return obj;
},
// core {}.hasOwnProperty shortcut
owns : function ( obj, field ) {
return Object( obj ).hasOwnProperty( field );
},
// native [].slice shortcut
// used to turn dynamic arguments[] to real array
slice : function ( args, m, n ) {
return aproto.slice.call( args, m, n );
},
// empties an object
// used by .off() method to empty evHandler functions cache
vacate : function ( obj ) {
for (
var l in obj
) {
try {
_.owns( Object.prototype, l )
|| ( delete obj[l] );
} catch( xc ) {}
}
return obj;
}
};
// main function uses this strings
// for subscribing/removing/executing handlers
var timerEvent = {
start : "tickStart",
stop : "tickStop",
tick : "tick",
end : "tickEnd"
};
return (function ( listener ) {
// main timer function
// @param1, float, optional, how often to fire 'tick' events, default == 1000, ( == 1sec )
// @param2, integer, optional, how many times to fire 'tick' event, default == Infinity
// returns, Object, object with following api:
//
// registering functions for 'timerEvent' events:
//
// .on( evType, func )
// # caches a function for given event type ( of 'timerEvent' object )
// .off( [ evType, func] )
// # unregisteres function for given event type
// # if no function is provided removes all functions registered for event 'evType'
// # if nothing is provided removes all registered functions
// .fire( evType [, ...params_for_registered_handlers ] )
// # runs functions registered for given event type
// # passing provided arguments to them, if any
// # used internaly when .start() method is called
//
// these are for controling timer object:
//
// .start([ ...params])
// # starts triggering 'tick' events updating internal state
// # passes provided parameters to triggerd functions,
// # ( available through .data property of object passed to handlers )
// .stop()
// # pauses triggering 'tick' events ( if Timer object is in 'running state' )
// # triggers 'tickStop' event
// .reset()
// # nulls internal state, stops dispatching 'ticks', resets counter
// # triggers 'tickEnd' event
//
// these are for quering internal timer state:
//
// .currentCount()
// # how many times Timer fired so far
// # returns, integer
// .delay()
// # gives timer's delay
// # returns, float
// .repeatCount()
// # how many times timer will dispatch 'tick' events
// # returns, integer
// .running()
// # 'is running' state
// # returns, boolean
//
return function ( delay, fireCount ) {
return (function ( delay, fireCount ) {
// preconfigured object that will handle 'tick' events
var host = this;
// timer object's internal state
// used/updated by timer
var timerState =
{
currentCount : 0,
delay : Math.abs( parseFloat(delay) ) || 1000,
repeatCount : Math.abs( parseInt(fireCount) ) || Infinity,
running : false,
interval : undef
};
// hack to reset .currentCount property asynchronously in .reset() method
// without using it this way, ( by zeroing it directly, like: timerState.currentCount = 0 )
// will make last 'tick' function call report: .currentCount() == 0,
// instead of whatever the currentCount was
// at the time the 'last tick' dispatch was performed
//
// because the handlers are runned asyncronously, and
// because setting currentCount to 0 manualy ( synchronously )
// will reset it before last function gets to be runned
// reseting it asyncronously schedules a function to reset a property
// making 'last tick' function report correct currentCount ( not 0 ).
var zer0CurrentCount =
_.async(
function () {
timerState.currentCount = 0;
}
);
// holds arguments passed to last .start() call
// uses these for further .start() calls if no new arguments are given
// passes them to triggered functions
var fireargs = [];
// attaches timer api
// ( .start, .stop, .reset, .currentCount, .delay, .repeatCount, .running )
// to timer object
_.init(
host,
{
// handles starting event dispatch
// if arguments are given, caches and
// uses them for further calls
// 'keeps an eye' on timer's configuration options
// updating/aborting dispatch when/if necessary
// triggering corresponding events and functions
// does nothing if timer is already in 'active' state
start: function () {
var startargs;
host.running()
|| (
timerState.running = true,
( startargs = _.slice( arguments ) ).length
&& _.arrsub( fireargs, startargs ),
host.fire.apply(
host,
[timerEvent.start]
.concat( fireargs )
),
timerState.currentCount += 1,
host.fire.apply(
host,
[timerEvent.tick]
.concat( fireargs )
),
( timerState.currentCount == timerState.repeatCount )
&& host.reset()
|| (
timerState.interval =
setInterval(
function () {
timerState.currentCount += 1;
host.fire.apply(
host,
[timerEvent.tick]
.concat( fireargs )
);
( timerState.currentCount >= timerState.repeatCount )
&& host.reset();
},
timerState.delay
)
)
);
return host;
},
// pauses running functions ( if timer{} is in 'running' state )
// fires 'tickStop' event
// passes arguments ( given in .start call ) to cached functions
// updates timer's internal state
stop: function () {
host.running()
&& (
( timerState.interval !== undef )
&& (
clearInterval( timerState.interval ),
timerState.interval = undef
),
timerState.running = false,
host.fire.apply(
host,
[timerEvent.stop]
.concat(fireargs)
)
);
return host;
},
// cancels event dispatch
// nulls internal state
// fires 'tickEnd' functions
reset: function () {
( timerState.interval !== undef )
&& (
clearInterval( timerState.interval ),
timerState.interval = undef
);
timerState.running = false;
host.fire.apply(
host,
[timerEvent.end]
.concat( fireargs )
);
zer0CurrentCount();
return host;
},
// query timer's current state:
currentCount: function () {
return timerState.currentCount;
},
delay: function () {
return timerState.delay;
},
repeatCount: function () {
return timerState.repeatCount;
},
running: function () {
return timerState.running;
}
}
);
return host;
}).call( listener( {} ), delay, fireCount );
}
})(
// function to configure an object to handle custom events
// gives basic event handling functionality to provided object
// attaches .on/.off/.fire methods to it,
// used by main Timer function
// ( to generate base objects for handling timer events )
// passed as single ( private ) argument to code above
function ( obj ) {
if (
_.isobj(obj)
) {
// evHandler parameter object is used to store provided handlers in
(function ( evHandlers ) {
// plain object to configure for custom event handling
var host = this;
// attaches api ( .on, .off, .fire ) to provided object
_.init(
host,
{
// if function is provided cache it in 'evHandlers' object
// ( to be called when needed )
// both, event type and function argument, are required
on: function ( evtype, fn ) {
if (
_.isvalid( evtype )
&& _.isfn( fn )
) {
_.owns( evHandlers, evtype )
&& evHandlers[evtype].push( fn )
|| ( evHandlers[evtype] = [fn] );
}
return host;
},
// deletes a function ( registered for evtype ) from evHandlers{}
// both parameters are optional
off: function ( evtype, fn ) {
if (
_.isvalid( evtype )
) {
if (
_.owns( evHandlers, evtype )
) {
_.isfn( fn )
&& (
_.gc.call( evHandlers[evtype], fn ),
evHandlers[evtype].length
|| ( delete evHandlers[evtype] ), 1
)
|| (
_.empty( evHandlers[evtype] ),
delete evHandlers[evtype]
);
}
} else {
_.owneach(
evHandlers,
function ( evtype, fns ) {
_.empty( fns );
}
);
_.vacate( evHandlers );
}
return host;
},
// triggers functions registered for ( string ) evtype event
// passes 'event{}' to handlers
// it holds event type ( .type ),
// data[] ( .data ) provided through .fire call,
// object through which method is called ( .target )
// and current execting function ( .handler )
// runs handlers asynchronusly by passing them to
// _.async() method before execution
fire: function ( evtype ) { // ( any )...args
if (
_.isvalid( evtype )
) {
if (
_.owns( evHandlers, evtype )
) {
var fireargs = _.slice( arguments, 1 );
_.arreach(
evHandlers[evtype],
function ( evhandler ) {
_.async( evhandler ).call(
host,
{
type : evtype,
data : fireargs,
target : host,
handler : evhandler
}
);
}
);
}
}
return host;
}
}
);
}).call(
obj, // passed object to apply event handling functionality to
{} // plain object to cache registered functions in
);
}
// gives back passed/configued object
return obj;
}
);
}
));
//
// use:
//
// set event dispatch frequency 2x/sec
// run it 5x ( skip second argument to run functions indefinitely )
// check out the console
var timerObj = Timer( 1000 / 2, 5 );
// shortcut function to start the timer
function goTimer () {
// start 'ticking' functions,
// pass arbitrary arguments to handlers
timerObj.start(
Math.random(),
( new Date ).valueOf()
);
}
// register functions for 'tick' cycle
timerObj
.on(
"tickStart",
function ( e ) {
console.clear();
console.log(
e.type + ", \n",
( new Date ).valueOf()
);
}
)
.on(
"tick",
function ( e ) {
// updateStuff();
console.log(
e.type + "#1, "
, "#", this.currentCount(),", "
, e.data
);
}
)
.on(
"tick",
function ( e ) {
// updateStuff();
console.log(
e.type + "#2, "
, "Math.random() < Math.random(): "
, Math.random() < Math.random()
);
}
)
.on(
"tickEnd",
function ( e ) {
console.log(
e.type + ", \n"
, "e.target === this: "
, e.target === this
, ", e.target === timerObj: "
, e.target === timerObj
, "."
);
setTimeout( goTimer, 10000 * Math.random() );
}
);
//
setTimeout( goTimer, 2000 );
//
//
//
//