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); >>> + } >>> >>> >>> } >> >