I would assume that goog.bind would be optimized by gcc if it can be (perhaps it is inlined if it uses es5 function.protoype.bind internally- I did not look inside it)
The function naming/caching in Language.closure is important, including private naming conventions when they are needed for closures. Did you test this with your chsnges: var f1:Function = myInst.method; var f2:Function = myInst.method; trace(f1 == f2) On Thu, 6 Jan 2022, 1:37 am Harbs, <harbs.li...@gmail.com> wrote: > 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); > >>> + } > >>> > >>> > >>> } > >> > > > >