AS3 how to return EventListener value - actionscript-3

If I have code that looks like this:
public function getNetStreamPublishClientList():Array
{
var ncStreamListResults = new Object()
ncStreamListResults.onResult = function(list:Array)
{
//this needs to be returned from getNetStreamPublishClientList
return list;
}
this.nc.call("getStreamClientIds",
new Responder(ncStreamListResults.onResult),
this.streamName);
}
how can I return the value of list from getNetStreamPublishClientList?

use global item for list

It looks like you won't be able to know the value of list at the point that getNetStreamPublishClientList() finishes executing.
This is because the nc object will probably not have finished its work by that time, and in that case the completion handler (currently assigned to be onResult) won't have been called.
Whatever is waiting on the result of this function, I'd change it to wait for an event. Possibly use a member function to act as the onResult handler.

Related

nested function cant find itself in Typescript

I have the following code:
//Main Entry Point.
start() {
this.init();
this.gameLoop();
}
//Init, runs only once.
init() {
let initalEntity1: Entity = new Entity(10, 10, Gender.female);
let initalEntity2: Entity = new Entity(60, 60, Gender.male);
console.log("There are " + this.Entities.length + " Items in the entities Array")
this.Entities.push(initalEntity1, initalEntity2);
console.log("There are " + this.Entities.length + " Items in the entities Array")
}
gameLoop() {
console.log("Performing a Game Loop");
requestAnimationFrame(this.gameLoop);
//MAIN LOOP THROUGH ENTITIES
for (let i in this.Entities) {
this.Render.drawEntitysToScreen(this.Entities[i].EntityPosition, this.Entities[i].gender);
}
}
It enters into start() fine, and also performs all of the init() functionality. it them proceeds onto gameloop() which it will run once, however the line requestAnimationFrame(this.gameLoop); which is ment to retrigger the function to be called as a Canvas frame is causing the following error:
TypeError: this is undefined
trying to requestAnimationFrame(gameLoop); but it causes the typescript compiler to get upset...
This is due to how this binding works in javascript. The way by which you are passing this.gameLoop to requestAnimationFrame is essentially passing an unbound gameLoop function, and so when it is called, it has lost reference to its this.
There are a number of possible solutions to this problem:
You can bind this.gameLoop to this inside of the class constructor, like so:
constructor() {
this.gameLoop = this.gameLoop.bind(this);
}
You can bind this.gameLoop to this as part of the gameLoop method definition. Rather than defining gameLoop like
gameLoop() {
If you instead use
gameLoop = () => {
it will be automatically bound to this. This is a property of using the fat arrow for function declarations: it automatically performs binding to the this that exists at the function declaration.
You can change how you pass gameLoop to requestAnimationFrame:
requestAnimationFrame(() => this.gameLoop());
This again takes advantage of the automatic this binding performed by the arrow function, but instead of doing it as part of the class method declaration you can simply do it lazily at the time you need it to be bound.
Note, however, that doing it this way does mean that a new function will be created each time gameLoop is called.
When you call this.gameLoop() within start, the value for this inside gameLoop's body will be the class gameLoop belongs to, because you call gameLoop as a property of this (the class).
When you pass a function reference its value for this might be anything when the function is called from somewhere else.
Solution 1 | Using Function.prototype.bind
bind the value for this as you give the function to requestAnimationFrame. By doing this you explicitly say:
Let the argument to bind be this inside any call to gameLoop, regardless of how it is called, or where it is called from.
requestAnimationFrame(this.gameLoop.bind(this));
Note that bind returns you a new function, so the original gameLoop function that is still a property of your class remains unchanged.
Solution 2 | Using an arrow function
Define an arrow function to eventually execute the call to gameLoop instead of requestAnimationFrame. The this value within arrow functions is static, and is inherited from the execution context enclosing the function declaration.
requestAnimationFrame(() => this.gameLoop());

Create delay in ActionScript 3 function

I have a function in Adobe Flex 4 (ActionScript 3) that accepts an object and returns an ArrayCollection...
If a certain global variable is set to true, I want the function to delay itself for 3 seconds before running. Otherwise I want the function to run as normal.
The problem is, if I use a Timer, that timer calls a separate function, and that function cannot return anything to my calling function, nor can the function it calls accept any parameters, so it's not like I can call my own function recursively after the TimerComplete event fires... And a recursive call wouldn't work anyway, because it would return the ArrayCollection to the timer-result function, not to the original calling function...
I need a delay within the function, not a delay that causes me to go outside that function. But I cannot figure out how to do it.
Something like this is what I need to do:
private function createArrayCollection(myObject:Object):ArrayCollection {
var myArrayCollection:ArrayCollection = new ArrayCollection();
if (globalWaitBoolean) {
//delay here for 3 seconds, somehow
}
//Here I do the stuff that uses the info in myObject to figure out what to
//put into the ArrayCollection I want to return
return (myArrayCollection);
}
So... Any ideas on how to accomplish this without calling an external Timer function that cannot return an object back to my original function?
Thanks,
The way you want it you will have your whole application to lag for 3 seconds, unresponsive to any user input and external events. But it is possible, sure:
import flash.utils.getTimer;
private function createArrayCollection(myObject:Object):ArrayCollection
{
var myArrayCollection:ArrayCollection = new ArrayCollection;
if (globalWaitBoolean)
{
var waitUntil:int = getTimer() + 3000;
// Method getTimer() returns time in ms passed since app start.
// So you just have to wait until it is greater than appointed time.
while (getTimer() < waitUntil)
{
// Do nothing.
}
}
return (myArrayCollection);
}
Still, if you want to do it in a correct way of doing it:
import flash.utils.setTimeout;
private function callerMethod():void
{
// Blah blah blah.
// ...
// Finally.
createArrayCollection(sourceData, asyncResult);
}
private function createArrayCollection(myObject:Object, handler:Function):void
{
var result:ArrayCollection = new ArrayCollection;
if (globalWaitBoolean) setTimeout(handler, 3000, result);
else handler(result);
}
private function asyncResult(source:ArrayCollection):void
{
// The rest of your processing code.
}
Normal (synchronous) code flow would not return until the value is prepared, so should you desire to actually wait for 3 seconds while not allowing your app to do anything, use getTimer() approach from #Organis's answer. If you'll go for an asynchronus result, you'll need to face and overcome some more problems.
First, when do you expect your returned ArrayCollection to actually arrive. Speaking of code design, asynchronous code requires a whole lot of assumptions, thread safety etc etc, and even while AS3/Flash does not have true multithreading unless you count Workers, the code flow with events is not as obvious. So, whoever called your createArrayCollection() MUST NOT expect value returned from it right away. So, speaking about your direct question, NO, you can't avoid timers of some sort if you desire a responsive application. But you can use them with an approach that would involve an indirectly returned result.
Second, whether there might be concurring requests for more array collections from objects if your app would require these - you have to prepare for any kind of interference that might be caused by this. Say your function is triggered by a button click - what if that button would get clicked more than once in 3 seconds?
Third, actual route to processing code is not direct with asynchronous return. You need either a callback, an event handler (which is essentially a semi-native callback), a code that periodically checks for value presence (enter frame handler, etc) or a similar trick to gather the value that's returned asynchronously, and then transfer it to any relevant code that would process it further. Therefore, you would need to design an interface capable of receiving complex data (source object forward, array collection backward) and then carefully test it against all the possible cases and flaws.
An example of implementing all that is very long, I'll try to outline it somehow. Ler's assume you have a sort of "server" class that accepts requests for data and processes it synchronously (no wait) or asynchronously (wait). It accepts a source object of type "T" and provides a newly created object of type ArrayCollection, supplied as a parameter to whatever callback function sent to it. Also it accepts a delay (a simple way to show sync/async return would be a boolean, but why not getting an int?) as a parameter, and guarantees (to the extent of event model limitations) that after this delay the callback will be called ASAP. The architecture will then look like this:
class Processor {
Dictionary requests; // here all the requests that are delayed will be stored
public function dpr(source:T,callback:Function,delay:int=0):void{...}
// creates requests and stores them
private function syncProcess(source:T):ArrayCollection {...}
// whatever routine you want to get variably delayed
private function processTimeout(e:Event=null):void {...}
// processes events from "setTimeout()" and calls callbacks
}
Note that asynchronous approach forced to create three more entities than a synchronous one. First is the request holding structure (the dictionary here), second is timeout event handler, third is whatever callback you'll desire to get called when the data is ready. The code flow would go like this:
Synchronous call would result in the callback directly called from within the class: request->processTimeout->syncProcess()->callback. Asynchronous call will have the callback called from within Timer::timerComplete event handler via setTimeout called within request, with data that originally came from request stored in requests.
You could use an embedded/inline function:
private function createArrayCollection(myObject:Object):ArrayCollection {
var myArrayCollection:ArrayCollection = new ArrayCollection();
if (globalWaitBoolean) {
var milliseconds:int = 3000;
//delay here for 3 seconds
setTimeout(function()
{
//Here I do the stuff that uses the info in myObject to figure out what to
//put into the ArrayCollection I want to return
return (myArrayCollection);
},
milliseconds);
}
else
{
//Here I do the stuff that uses the info in myObject to figure out what to
//put into the ArrayCollection I want to return
return (myArrayCollection);
}
}
The inner function will have access to all local vars of the outer function.

AS3: Returning value from another function after event happened

Basically I want to check if a user exists in a database using AMF (and that works great!). But then I want to return the boolean value to another function (in another class) that originally called the "checkUserExistance" function. But, since the database connection isn't immidiate, this function will always return a false value (even if "result" is true). So I would like to have the return-line inside the "onUserChecked"-function but that of course gives me an error. I thought I could create an eventListener, but then, the "return userExists"-line would also have to be inside another function, which doesnät work(?)... What can I do?
public function checkUserExistance(username:String) {
var responderBOOLEAN:Responder = new Responder(onUserChecked, onFault)
var userExists:Boolean = false;
connection.connect(gateway);
connection.call("User.checkUser", responderBOOLEAN, username);
connection.close();
function onUserChecked(result:Boolean):void {
userExists = result;
}
return userExists;
}
I'm sorry but you are trying to force an Asynchronous call to a Synchronous one and this is WRONG.
See here
You should learn how to handle events in the correct way.
What can i suggest you that helped me a lot is this
The only true answer here is to save userExists as a member variable, and dispatch event when the server returns you a response. The client side of the things should be similar to:
// add listener, ServerEvent is a custom event (see below)
server.addEventListener(ServerEvent.CHECK_RESPONSE, onCheckResponse);
server.checkUserExistance('username'); // start the query
function onCheckResponse(e:ServerEvent):void {
if (e.userExists) {
}
}
// inside server class
function onUserChecked(result:Boolean):void {
userExists = true;
dispatchEvent(new ServerEvent(ServerEvent.CHECK_RESPONSE, userExists));
}
/* ServerEvent is a custom class that extens Event
Such classes are used so you can pass special properties in them
via constructor (pass data, store it into member variable)
and through getter for that variable.
If you don't like it, simply add/dispatch Event.COMPLETE
and use public property to get userExists from server
*/

ActionScript 3: Assigning a named function to a variable of type Function

I'm working with a game loop and am attempting to handle user input by assigning various methods to a variable of type Function depending on the games state.
I'm assigning a defined function called InputState1 to my Function variable inputFunction:
var inputFunction:Function = InputState1;
where InputState1 is:
public function InputState1():void
{
// input logic
}
and call inputFunction in the game loop's update method:
override protected function update(timeDelta:Number):void
{
trace(inputFunction);
inputFunction();
}
When I trace the inputFunction, it returns an empty function.
Is it possible to assign a named function to a function variable and if so, how would I go about doing this properly?
Solution: I was invoking my function variables call method instead of just calling the function. It works now.
What I have understood from your argument is that you want a game state to be identified and act according to it, well you always can define a String holding the game state value which updates as game state changes, and make a function returning that string,(or directly comapre that string wth defined states)
var gameState:String="initial";
override protected function update(timeDelta:Number,gameState:String):void
{
gameState="newstate"; //depending upon your condition requirement
}
if(gameState="requredState"){
//do required stuff
}
The issue was that I was invoking my function variable's call method instead of just calling the function. It works now and I've edited the code in my question to the correct version.

Recursive function with event listener in flex 4

I have written a function which is recursively called. I have maintained an array in which values are pushed with a listener of an event. But the problem is function is returned first without array increment and the listener is executed later.
public function getAllChilds(seltem:XML, allChilds:Array): Array
{
if(//the childs of selected item if need to retrive from server)
var viewChildrenJobsService : HTTPService = new HTTPService();
viewChildrenJobsService.url = // here is my url ;
viewChildrenJobsService .addEventListener(ResultEvent.RESULT, function(event:ResultEvent):void {
// now on this result event i got all childs of selected item.
for each(var childJob :XML in seltem.children())
{
allChilds.push(childJob);
if (//the childs of childJob need to retrive from server)
allChilds = getAllHierarchicalChilds(childJob, allChilds);
}
});
return allChilds;
}
Is there any way to overcome this problem so that the function will return after the completion of the event?
ok , you are returning allchilds before the Result Event. You erase the original question ;) , so i dont remember if your problem was this.
Try to split the function : First the request, then get the value of allChild.
and yes ... is better to write (and paste) good formatted code : its easier to understand.