My problem with apply was user error because I was using spread arguments which 
was actually creating an arrays of arrays.

But my question about Language.closure stands.

In my tests it looks like that works.

> On Jan 5, 2022, at 2:21 PM, Harbs <harbs.li...@gmail.com> wrote:
> 
> So this is weird.
> 
> Function.prototype.apply is supposed to be able to take an array of arguments 
> and apply them to another function. (different from call where you have to 
> specify the arguments separately.)
> 
> It looks to me like a function which was bound to an object (such as one 
> wrapped by Language.closure) has the array passed into the first argument as 
> an array instead of being passed in as a list of arguments.
> 
> I have not seen this documented anywhere, but that’s what I’m seeing.
> 
> Hmm. Actually, not sure about this. goog.bind is doing some weird stuff. 
> Maybe that’s causing what I’m seeing? Why are we using goog.bind and not just 
> the following in Language.closure?
> 
> static public function closure(fn:Function, object:Object):Function {
>  return function() {
>    return fn.apply(object, arguments);
>  };
> }
> 
> My understanding is that code will correctly bind the function call to this.
> 
> It’s simpler, doesn’t require goog.bind and doesn’t require passing in 
> function names.
> 
> Am I missing something?
> 
> Harbs
> 
>> On Jan 5, 2022, at 9:37 AM, Harbs <harbs.li...@gmail.com> wrote:
>> 
>> This function is a cool one. It lets you animate *anything*. You just 
>> specify a target fps and run an arbitrary function and it’ll automatically 
>> be spaced to execute at the target speed:
>> 
>> The following will increment a value once every 50ms (1000/20fps) and run 
>> exactly 30 times.
>> 
>> var value:Number = 0;
>> function increment(val:Number):void{
>>      value+=val;
>> }
>> var animated:Function = animateFunction(increment,20);
>> var savedValue:Number;
>> for(i=0;i<30;i++){
>>      animated(1);
>> }
>> 
>> Have fun! B-)
>> Harbs
>> 
>>> On Jan 5, 2022, at 9:31 AM, ha...@apache.org wrote:
>>> 
>>> This is an automated email from the ASF dual-hosted git repository.
>>> 
>>> harbs pushed a commit to branch develop
>>> in repository https://gitbox.apache.org/repos/asf/royale-asjs.git
>>> 
>>> 
>>> The following commit(s) were added to refs/heads/develop by this push:
>>>   new dd1c6e4  Added animateFunction
>>> dd1c6e4 is described below
>>> 
>>> commit dd1c6e4cd7b082207a39efbf71de31adbb6de0d9
>>> Author: Harbs <ha...@in-tools.com>
>>> AuthorDate: Wed Jan 5 09:31:10 2022 +0200
>>> 
>>>  Added animateFunction
>>> ---
>>> .../projects/Core/src/main/royale/CoreClasses.as   |   1 +
>>> .../royale/utils/functional/animateFunction.as     | 130 
>>> +++++++++++++++++++++
>>> .../src/test/royale/flexUnitTests/CoreTester.as    |   2 +-
>>> .../test/royale/flexUnitTests/FunctionalTests.as   |  34 ++++++
>>> 4 files changed, 166 insertions(+), 1 deletion(-)
>>> 
>>> diff --git a/frameworks/projects/Core/src/main/royale/CoreClasses.as 
>>> b/frameworks/projects/Core/src/main/royale/CoreClasses.as
>>> index 50c3c71..48189b5 100644
>>> --- a/frameworks/projects/Core/src/main/royale/CoreClasses.as
>>> +++ b/frameworks/projects/Core/src/main/royale/CoreClasses.as
>>> @@ -382,6 +382,7 @@ internal class CoreClasses
>>>     import org.apache.royale.utils.functional.debounceLong; debounceLong;
>>>     import org.apache.royale.utils.functional.debounceShort; debounceShort;
>>>     import org.apache.royale.utils.functional.throttle; throttle;
>>> +   import org.apache.royale.utils.functional.animateFunction; 
>>> animateFunction;
>>> 
>>>     import org.apache.royale.core.TextLineMetrics; TextLineMetrics;
>>>     import org.apache.royale.utils.ClassSelectorList; ClassSelectorList;
>>> diff --git 
>>> a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/functional/animateFunction.as
>>>  
>>> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/functional/animateFunction.as
>>> new file mode 100644
>>> index 0000000..32b9fbf
>>> --- /dev/null
>>> +++ 
>>> b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/functional/animateFunction.as
>>> @@ -0,0 +1,130 @@
>>> +////////////////////////////////////////////////////////////////////////////////
>>> +//
>>> +//  Licensed to the Apache Software Foundation (ASF) under one or more
>>> +//  contributor license agreements.  See the NOTICE file distributed with
>>> +//  this work for additional information regarding copyright ownership.
>>> +//  The ASF licenses this file to You under the Apache License, Version 2.0
>>> +//  (the "License"); you may not use this file except in compliance with
>>> +//  the License.  You may obtain a copy of the License at
>>> +//
>>> +//      http://www.apache.org/licenses/LICENSE-2.0
>>> +//
>>> +//  Unless required by applicable law or agreed to in writing, software
>>> +//  distributed under the License is distributed on an "AS IS" BASIS,
>>> +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
>>> implied.
>>> +//  See the License for the specific language governing permissions and
>>> +//  limitations under the License.
>>> +//
>>> +////////////////////////////////////////////////////////////////////////////////
>>> +package org.apache.royale.utils.functional
>>> +{
>>> +   COMPILE::SWF{
>>> +           import flash.utils.setTimeout;          
>>> +           import flash.utils.clearTimeout;                
>>> +   }
>>> +   /**
>>> +    * Returns a debounced function to run after a delay.
>>> +    * The first invocation of the function will be run after its delay.
>>> +    * Any invocations between the first invocation and the delay will be 
>>> ignored.
>>> +    * 
>>> +   * @royalesuppressexport
>>> +    * @langversion 3.0
>>> +    * @productversion Royale 0.9.9
>>> +    * 
>>> +    */
>>> +   public function animateFunction(method:Function, fps:Number):Function
>>> +   {
>>> +           COMPILE::SWF
>>> +           {
>>> +                   var limit:Number = 1000/fps;
>>> +                   var timeStamp:Number = 0;
>>> +                   var timeoutRef:*;
>>> +                   var invocations:Array = [];
>>> +                   return function(...args):void
>>> +                   {
>>> +                           if(timeoutRef){
>>> +                                   clearTimeout(timeoutRef);
>>> +                                   timeoutRef = null;
>>> +                           }
>>> +                           invocations.push(args);
>>> +                           var currentTime:Number = new Date().getTime();
>>> +                           var timeDiff:Number = currentTime - timeStamp;
>>> +                           if(timeDiff >= limit)
>>> +                           {
>>> +                                   if(timeStamp == 0)
>>> +                                           timeStamp = currentTime;
>>> +                                   else
>>> +                                           timeStamp += limit;
>>> +                                   method.apply(null,invocations.shift());
>>> +                           }
>>> +                           if(invocations.length && timeoutRef == null)
>>> +                           {
>>> +                                   // currentTime = new Date().getTime();
>>> +                                   timeDiff = currentTime - timeStamp + 
>>> limit;
>>> +                                   var nextInterval:Number = 
>>> Math.max(timeDiff,0);
>>> +                                   timeoutRef = setTimeout(callback, 
>>> nextInterval);
>>> +                           }
>>> +
>>> +                           function callback():void
>>> +                           {
>>> +                                   timeoutRef = null;
>>> +
>>> +                                   if(!invocations.length)
>>> +                                           return;
>>> +                                   
>>> +                                   var currentArgs:Array = 
>>> invocations.shift();
>>> +                                   method.apply(null,currentArgs);
>>> +                                   timeStamp += limit;
>>> +                                   var timeDiff:Number = new 
>>> Date().getTime() - timeStamp + limit;
>>> +                                   while(timeDiff < 0)
>>> +                                   {
>>> +                                           // catch up on the missing 
>>> frames
>>> +                                           
>>> method.apply(null,invocations.shift());
>>> +                                           if(invocations.length == 0)
>>> +                                           {
>>> +                                                   return;
>>> +                                           }
>>> +                                           timeDiff+=limit;
>>> +                                   }
>>> +                                   if(invocations.length)
>>> +                                   {
>>> +                                           timeoutRef = 
>>> setTimeout(callback, timeDiff);
>>> +                                   }
>>> +                           }
>>> +                   }
>>> +
>>> +           }
>>> +
>>> +           COMPILE::JS
>>> +           {
>>> +                   var limit:Number = 1000/fps;
>>> +                   var lastTimeStamp:Number = 0;
>>> +                   var timeoutRef:*;
>>> +                   var invocations:Array = [];
>>> +                   return function(...args):void
>>> +                   {
>>> +                           invocations.push(args);
>>> +                           requestAnimationFrame(callback);
>>> +                           function callback(timeStamp:Number):void
>>> +                           {
>>> +                                   if(invocations.length == 0)
>>> +                                           return;
>>> +
>>> +                                   // we can't rely on getting time stamps 
>>> ourselves,
>>> +                                   // so hopefully this is not slower than 
>>> our target rate...
>>> +                                   if ( (timeStamp - lastTimeStamp) >= 
>>> limit)
>>> +                                   {
>>> +                                           if(lastTimeStamp == 0)
>>> +                                                   lastTimeStamp = 
>>> timeStamp;
>>> +                                           else
>>> +                                                   lastTimeStamp += limit; 
>>> // make sure we stick to the desired rate
>>> +
>>> +                                           
>>> method.apply(null,invocations.shift());
>>> +                                   }
>>> +                                   if(invocations.length)
>>> +                                           requestAnimationFrame(callback);
>>> +                           }
>>> +                   }
>>> +           }
>>> +   }
>>> +}
>>> \ No newline at end of file
>>> diff --git 
>>> a/frameworks/projects/Core/src/test/royale/flexUnitTests/CoreTester.as 
>>> b/frameworks/projects/Core/src/test/royale/flexUnitTests/CoreTester.as
>>> index 7b15375..eeb4e76 100644
>>> --- a/frameworks/projects/Core/src/test/royale/flexUnitTests/CoreTester.as
>>> +++ b/frameworks/projects/Core/src/test/royale/flexUnitTests/CoreTester.as
>>> @@ -45,7 +45,7 @@ package flexUnitTests
>>>       public var sanitizerTest:SanitizeTest;
>>>       public var eventsTest:EventsTest;
>>>       public var objectUtilTests:ObjectUtilsTest;
>>> -        public var functionelTests:FunctionalTests;
>>> +        public var functionalTests:FunctionalTests;
>>> 
>>>   }
>>> }
>>> diff --git 
>>> a/frameworks/projects/Core/src/test/royale/flexUnitTests/FunctionalTests.as 
>>> b/frameworks/projects/Core/src/test/royale/flexUnitTests/FunctionalTests.as
>>> index 022c4da..75f320c 100644
>>> --- 
>>> a/frameworks/projects/Core/src/test/royale/flexUnitTests/FunctionalTests.as
>>> +++ 
>>> b/frameworks/projects/Core/src/test/royale/flexUnitTests/FunctionalTests.as
>>> @@ -25,6 +25,8 @@ package flexUnitTests
>>>   import org.apache.royale.test.asserts.*;
>>>     import org.apache.royale.test.async.*;
>>>   import org.apache.royale.utils.functional.*;
>>> +    import org.apache.royale.utils.functional.animateFunction;
>>> +    import org.apache.royale.test.asserts.assertTrue;
>>> 
>>>   public class FunctionalTests
>>>   {         
>>> @@ -192,6 +194,38 @@ package flexUnitTests
>>>               assertEquals(value,7,"value should be 7");
>>>           }, 300);
>>>       }
>>> +        [Test(async,timeout="300")]
>>> +        public function testAnimate():void
>>> +        {
>>> +            var foo:Foo = new Foo();
>>> +            var animateThis:Function = animateFunction(foo.increment,20);
>>> +            for(var i:int=0;i<30;i++){
>>> +                animateThis(1);
>>> +            }
>>> +            var savedThisValue:Number;
>>> +            setTimeout(function():void{
>>> +                savedThisValue = foo.value;
>>> +            },50);
>>> +
>>> +            var value:Number = 0;
>>> +            function increment(val:Number):void{
>>> +                value+=val;
>>> +            }
>>> +            var animated:Function = animateFunction(increment,20);
>>> +            var savedValue:Number;
>>> +            for(i=0;i<30;i++){
>>> +                animated(1);
>>> +            }
>>> +
>>> +            setTimeout(function():void{
>>> +                savedValue = value;
>>> +            },50);
>>> +            Async.delayCall(this, function():void
>>> +            {
>>> +                assertTrue(savedThisValue<3,"foo value should be 2");
>>> +                assertTrue(savedValue<3,"value should be 2");
>>> +            }, 300);
>>> +        }
>>> 
>>> 
>>>   }
>> 
> 

Reply via email to