/* * ASDeferred Class for ActionScript3.0 * Copyright (c) 2008 munegon ( www.voidelement.com ) * * Version:: 0.1 * License:: MIT * * * refer to JSDeferred * Copyright (c) 2007 cho45 ( www.lowreal.net ) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package { import flash.utils.Timer; import flash.events.TimerEvent; public class ASDeferred { private var _next:ASDeferred; public var callback:Object; public var canceller:Function; public function ASDeferred() { init(); } public function init():ASDeferred { _next = null; callback = { ok: function( x:* ):* { return x; }, ng: function( x:* ):* { return x; } }; return this; } public function next( func:Function ):ASDeferred { return _post("ok", func ); } public function error( func:Function ):ASDeferred { return _post("ng", func ); } public function call( value:* = null ):ASDeferred { return _fire("ok", value ); } public function fail( err:* = null ):ASDeferred { return _fire("ng", err ); } public function cancel():ASDeferred { if ( canceller is Function ) { canceller(); } return init(); } private function _post( okng:String, func:Function ):ASDeferred { _next = new ASDeferred(); _next.callback[ okng ] = func; return _next; } private function _fire( okng:String, value:* ):ASDeferred { var next:String = "ok"; try { value = callback[ okng ].call( this, value ); } catch ( e:Error ) { next = "ng"; value = e; } if ( value is ASDeferred ) { value._next = _next; } else { if ( _next ) _next._fire( next, value ); } return this; } public static function loop( n:*, func:Function ):ASDeferred { var o:Object = { begin : n.hasOwnProperty("begin") ? n.begin : 0, end : n.hasOwnProperty("end") ? n.end : n - 1, step : n.hasOwnProperty("step") ? n.step : 1, last : false, prev : null }; var ret:*; var step:int = o.step; return ASDeferred.next( function():ASDeferred { function _loop( i:int ):* { if ( i <= o.end ) { if ( i + step > o.end ) { o.last = true; o.step = o.end - i + 1; } o.prev = ret; ret = func.apply( this, [ i, o ] ); if ( ret is ASDeferred ) { return ret.next( function( r:* ):* { ret = r; return _loop( i + step ); }); } else { _loop( i + step ); } } else { return ret; } } return _loop( o.begin ); }); } public static function parallel( dl:Object ):ASDeferred { var ret:ASDeferred = new ASDeferred(); var values:* = ( dl is Array ) ? [] : {}; var num:int = 0; for ( var i:String in dl ) { if ( dl.hasOwnProperty( i ) ) { ( function( d:ASDeferred, i:String ):void { d.next( function( v:* ):void { values[i] = v; if ( --num <= 0 ) { ret.call( values ); } }).error( function( e:* ):void { ret.fail( e ); }); num++; /* // parallel を直列で定義できるようにするための挿入コード var timer:Timer = new Timer( 0, 1 ); var complete:Function = function( e:TimerEvent ):void { timer.removeEventListener( e.type, arguments.callee ); d.call(); } timer.addEventListener( TimerEvent.TIMER_COMPLETE, complete ); timer.start(); d.canceller = function():void { try { timer.stop(); timer.removeEventListener( TimerEvent.TIMER_COMPLETE, complete ); } catch ( e:Error ) { } } //*/ })( dl[i], i ); } } if ( num == 0 ) { ASDeferred.next( function():void { ret.call() } ); } ret.canceller = function():void { for ( var i:String in dl ) { if ( dl.hasOwnProperty( i ) ) { dl[i].cancel(); } } } return ret; } public static function wait( n:Number ):ASDeferred { var d:ASDeferred = new ASDeferred(); var t:Date = new Date(); var timer:Timer = new Timer( n*1000, 1 ); var complete:Function = function( e:TimerEvent ):void { timer.removeEventListener( e.type, arguments.callee ); d.call( new Date().getTime() - t.getTime() ); } timer.addEventListener( TimerEvent.TIMER_COMPLETE, complete ); timer.start(); d.canceller = function():void { try { timer.stop(); timer.removeEventListener( TimerEvent.TIMER_COMPLETE, complete ); } catch ( e:Error ) { } } return d; } public function wait( n:Number ):ASDeferred { return next( function():ASDeferred { return ASDeferred.wait( n ) } ); } public function loop( n:*, func:Function ):ASDeferred { return next( function():ASDeferred { return ASDeferred.loop( n, func ) } ); } // parallel を直列で繋げられるようにするための追加メソッド public function parallel( dl:Object ):ASDeferred { return next( function():ASDeferred { return ASDeferred.parallel( dl ) } ); } public static function wrap( func:Function ):Function { return function( ...args:Array ):Function { return function():Function { return func.apply( null, args ); } } } public static function next( func:Function ):ASDeferred { var d:ASDeferred = new ASDeferred(); var timer:Timer = new Timer( 0, 1 ); var complete:Function = function( e:TimerEvent ):void { timer.removeEventListener( e.type, arguments.callee ); d.call(); } timer.addEventListener( TimerEvent.TIMER_COMPLETE, complete ); timer.start(); if ( func != null ) d.callback.ok = func; d.canceller = function():void { try { timer.stop(); timer.removeEventListener( TimerEvent.TIMER_COMPLETE, complete ); } catch ( e:Error ) { } } return d; } public static function call( func:Function, ...args:Array ):ASDeferred { return ASDeferred.next( function():* { return func.apply( this, args ); } ); } public static function define( obj:Object = null, list:Array = null ):Class { if ( !list ) list = ["parallel", "wait", "next", "call", "loop"]; if ( !obj ) obj = ( function():ASDeferred { return this } )(); for ( var i:int = 0; i < list.length; ++i ) { obj[ list[i] ] = ASDeferred[ list[i] ]; } return ASDeferred; } } }