Debounce job name - job name issue - polymer

Using Polymer 1.0...
The debounce method expects the job name to be some kind of object. I get Cannot read property 'foo' of undefined.
From documentation, the job name is a string. I thought the job name was just to reference the debounce object later, but I guess I am wrong.
What am I doing wrong here? Note, this is outside a custom element so that is why I am using Polymer.Base
function scrollSnap() {
Polymer.Base.debounce('foo', ()=> {
if (app.selected === 'portfolio') {
if (panel.scroller.scrollTop > 75 && panel.scroller.scrollTop < 200) {
panel.scroller.scrollTop = 400;
} else if (panel.scroller.scrollTop > 350 && panel.scroller.scrollTop < 400) {
panel.scroller.scrollTop = 0;
}
}
}, 1000)
}

This happens because the internal debouncer map is not initialized, so when Polymer tries to do a debouncer-name lookup, it dereferences an uninitialized/undefined array.
Since this debouncer call is being used outside a Polymer element, you'd have to manually call the setup function that would've normally been done in the element's initialization (i.e., _setupDebouncers()):
Polymer.Base._setupDebouncers();
for (let i=0; i<100; i++) {
Polymer.Base.debounce('foo', () => console.log('debounced'), 1000);
}
demo

Related

Eloquent Javascript Chapter 5 - JSON - Filtering, mapping (Higher-Order functions)

While explaining array filtering, by using a custom function, I'm having difficulty understanding part of the code (I'll list the function and how it's called below):
The specific line I have trouble with is the calling of the function:
console.log(filter(JSON.parse(ANCESTRY_FILE), function(person) { return person.born > 1900 && person.born < 1925; }))
Specifically, function(person) {...
Where does the argument person come from ? The code works fine, but up to this point I've never declared a function which takes an argument, but then is never passed that argument when it is called. Can someone explain this?
Worth mentioning is that we are filtering from a JSON object, which should be clear from the JSON.parse function used to extract data into an array. I've searched the JSON document and there is no mention of an entity or property by the name of 'person' there.
function filter(arr, test) {
//A custom function for filtering data from an array.
var passed = []; //Creating a new array here to keep our function pure.
for (i=0; i<arr.length; i++) { // Populate our new array with results
if (test(arr[i])) { // test = function(person) { return person.born > 1900 && person.born < 1925; }
passed.unshift(arr[i]); // unshift adds an element to the front of the array
}
}
return passed; //return our results.
}
// Where we call on our function and return the result.
console.log(filter(JSON.parse(ANCESTRY_FILE), function(person) { return person.born > 1900 && person.born < 1925; }))
Ok found the answer.
In case anyone else has a problem with understanding this, see below...
The filter function takes 2 arguments: an array, and a test function.
The test function in this case being:
function(person) { return person.born > 1900 && person.born < 1925; }
In the 'filter' function, we get this line:
if (test(arr[i])) {...
so basically we're getting:
if (arr[i].born > 1900 && arr[i].born < 1925) {..
So the 'person' argument in the nameless function is being passed the moment the function is actually being called from within its 'filter' parent function.

Execution order in NodeJS [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 4 years ago.
The community reviewed whether to reopen this question 3 months ago and left it closed:
Duplicate This question has been answered, is not unique, and doesn’t differentiate itself from another question.
I am running an event loop of the following form:
var i;
var j = 10;
for (i = 0; i < j; i++) {
asynchronousProcess(callbackFunction() {
alert(i);
});
}
I am trying to display a series of alerts showing the numbers 0 through 10. The problem is that by the time the callback function is triggered, the loop has already gone through a few iterations and it displays a higher value of i. Any recommendations on how to fix this?
The for loop runs immediately to completion while all your asynchronous operations are started. When they complete some time in the future and call their callbacks, the value of your loop index variable i will be at its last value for all the callbacks.
This is because the for loop does not wait for an asynchronous operation to complete before continuing on to the next iteration of the loop and because the async callbacks are called some time in the future. Thus, the loop completes its iterations and THEN the callbacks get called when those async operations finish. As such, the loop index is "done" and sitting at its final value for all the callbacks.
To work around this, you have to uniquely save the loop index separately for each callback. In Javascript, the way to do that is to capture it in a function closure. That can either be done be creating an inline function closure specifically for this purpose (first example shown below) or you can create an external function that you pass the index to and let it maintain the index uniquely for you (second example shown below).
As of 2016, if you have a fully up-to-spec ES6 implementation of Javascript, you can also use let to define the for loop variable and it will be uniquely defined for each iteration of the for loop (third implementation below). But, note this is a late implementation feature in ES6 implementations so you have to make sure your execution environment supports that option.
Use .forEach() to iterate since it creates its own function closure
someArray.forEach(function(item, i) {
asynchronousProcess(function(item) {
console.log(i);
});
});
Create Your Own Function Closure Using an IIFE
var j = 10;
for (var i = 0; i < j; i++) {
(function(cntr) {
// here the value of i was passed into as the argument cntr
// and will be captured in this function closure so each
// iteration of the loop can have it's own value
asynchronousProcess(function() {
console.log(cntr);
});
})(i);
}
Create or Modify External Function and Pass it the Variable
If you can modify the asynchronousProcess() function, then you could just pass the value in there and have the asynchronousProcess() function the cntr back to the callback like this:
var j = 10;
for (var i = 0; i < j; i++) {
asynchronousProcess(i, function(cntr) {
console.log(cntr);
});
}
Use ES6 let
If you have a Javascript execution environment that fully supports ES6, you can use let in your for loop like this:
const j = 10;
for (let i = 0; i < j; i++) {
asynchronousProcess(function() {
console.log(i);
});
}
let declared in a for loop declaration like this will create a unique value of i for each invocation of the loop (which is what you want).
Serializing with promises and async/await
If your async function returns a promise, and you want to serialize your async operations to run one after another instead of in parallel and you're running in a modern environment that supports async and await, then you have more options.
async function someFunction() {
const j = 10;
for (let i = 0; i < j; i++) {
// wait for the promise to resolve before advancing the for loop
await asynchronousProcess();
console.log(i);
}
}
This will make sure that only one call to asynchronousProcess() is in flight at a time and the for loop won't even advance until each one is done. This is different than the previous schemes that all ran your asynchronous operations in parallel so it depends entirely upon which design you want. Note: await works with a promise so your function has to return a promise that is resolved/rejected when the asynchronous operation is complete. Also, note that in order to use await, the containing function must be declared async.
Run asynchronous operations in parallel and use Promise.all() to collect results in order
function someFunction() {
let promises = [];
for (let i = 0; i < 10; i++) {
promises.push(asynchonousProcessThatReturnsPromise());
}
return Promise.all(promises);
}
someFunction().then(results => {
// array of results in order here
console.log(results);
}).catch(err => {
console.log(err);
});
async await is here
(ES7), so you can do this kind of things very easily now.
var i;
var j = 10;
for (i = 0; i < j; i++) {
await asycronouseProcess();
alert(i);
}
Remember, this works only if asycronouseProcess is returning a Promise
If asycronouseProcess is not in your control then you can make it return a Promise by yourself like this
function asyncProcess() {
return new Promise((resolve, reject) => {
asycronouseProcess(()=>{
resolve();
})
})
}
Then replace this line await asycronouseProcess(); by await asyncProcess();
Understanding Promises before even looking into async await is must
(Also read about support for async await)
Any recommendation on how to fix this?
Several. You can use bind:
for (i = 0; i < j; i++) {
asycronouseProcess(function (i) {
alert(i);
}.bind(null, i));
}
Or, if your browser supports let (it will be in the next ECMAScript version, however Firefox already supports it since a while) you could have:
for (i = 0; i < j; i++) {
let k = i;
asycronouseProcess(function() {
alert(k);
});
}
Or, you could do the job of bind manually (in case the browser doesn't support it, but I would say you can implement a shim in that case, it should be in the link above):
for (i = 0; i < j; i++) {
asycronouseProcess(function(i) {
return function () {
alert(i)
}
}(i));
}
I usually prefer let when I can use it (e.g. for Firefox add-on); otherwise bind or a custom currying function (that doesn't need a context object).
var i = 0;
var length = 10;
function for1() {
console.log(i);
for2();
}
function for2() {
if (i == length) {
return false;
}
setTimeout(function() {
i++;
for1();
}, 500);
}
for1();
Here is a sample functional approach to what is expected here.
ES2017: You can wrap the async code inside a function(say XHRPost) returning a promise( Async code inside the promise).
Then call the function(XHRPost) inside the for loop but with the magical Await keyword. :)
let http = new XMLHttpRequest();
let url = 'http://sumersin/forum.social.json';
function XHRpost(i) {
return new Promise(function(resolve) {
let params = 'id=nobot&%3Aoperation=social%3AcreateForumPost&subject=Demo' + i + '&message=Here%20is%20the%20Demo&_charset_=UTF-8';
http.open('POST', url, true);
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.onreadystatechange = function() {
console.log("Done " + i + "<<<<>>>>>" + http.readyState);
if(http.readyState == 4){
console.log('SUCCESS :',i);
resolve();
}
}
http.send(params);
});
}
(async () => {
for (let i = 1; i < 5; i++) {
await XHRpost(i);
}
})();
JavaScript code runs on a single thread, so you cannot principally block to wait for the first loop iteration to complete before beginning the next without seriously impacting page usability.
The solution depends on what you really need. If the example is close to exactly what you need, #Simon's suggestion to pass i to your async process is a good one.

ActionSctipt 3.0 Error:

I'm having real trouble trying to access the symbol dynamically, I have 9 buttons that all call this method, and they pass in their location (tl, t, tr, etc.) I've tried this method before on another program and it works without a problem, but in this program it fails.
I am attempting to access a symbol call s_tl (example location), but all I'm getting is undefined (see results).
function turn(btn : String):Function {
return function(e:MouseEvent) {
var players_turn : int;
var chosen : String = "s_" + btn;
trace(this);
trace(this[chosen]);
trace(chosen);
trace(this[chosen]);
// if crosses turn 0 else 1
if (s_c.currentFrame == 1) {
players_turn = 0;
} else {
players_turn = 1;
}
// check who's turn it is if it's been pressed before
if (players_turn == 0 && this[chosen].visible == false) {
this[chosen].gotoAndStop(1);
this[chosen].visible = true;
} else {
this[chosen].gotoAndStop(2);
this[chosen].visible = true;
}
};
}
Results:
[object global]
undefined
s_br
undefined
TypeError: Error #1010: A term is undefined and has no properties.
at MethodInfo-6()
Your problem is the bad code style. You define unnamed unbind function inside function turn() and that's where the root of your problem is. Unbind function exist, as your trace shows, in global addressing context and, unlike function turn(), is not bind to any specific display object. Your buttons probably exist on the same addressing context with turn(). Argument btn is available inside unnamed function because ECMA standard instructs so (if function A creates function B then local variables, including arguments, of A are available as local variables in B), but it is a very very very bad practice that makes code messy and induce headaches.
Please explain what you tried to achieve with that code so we could untangle it and rewrite in not-so-twisted way.
Okey, I basically figured you're doing Tic Tac Toe. Now, guideline. A cell must contain 3 frames: 1st frame for the button graphics, 2nd and 3rd for X and O. Name them your way: s_1, s_2, etc.
for (var i:int = 1; i < 10; i++)
{
var aCell:MovieClip = getChildByName("s_" + i) as MovieClip;
aCell.addEventListener(MouseEvent.CLICK, onTic);
}
function onTic(e:MouseEvent):void
{
var playersTurn:int = s_c.currentFrame;
var aCell:MovieClip = e.currentTarget as MovieClip;
trace(aCell.name);
// Now, the magic.
aCell.gotoAndStop(playersTurn + 1);
aCell.removeEventListener(MouseEvent.CLICK, onTic);
}

How do I jump back in history directly, I don't want the go() function to call back() multiple times

I'm using staterouter.js over the top of history.js. When I go back multiple pages, history.js internally calls back() the respective amount of times - and this is not desirable in my situation, because I have handler which is called for each intermediate call to back()
History.go = function(index,queue){
//History.debug('History.go: called', arguments);
// Prepare
var i;
// Handle
if ( index > 0 ) {
// Forward
for ( i=1; i<=index; ++i ) {
History.forward(queue);
}
}
else if ( index < 0 ) {
// Backward
for ( i=-1; i>=index; --i ) {
History.back(queue);
}
}
else {
throw new Error('History.go: History.go requires a positive or negative integer passed.');
}
// Chain
return History;
};
Is there any way around this behaviour?
I created my own function which I call when I need the behaviour as described above. It requires my own application layer implementation to be able to ignore routing callbacks for all but one of the abs(qty) history movements.
goDirect = function (qty) {
if (qty === -1 || qty === 1) {
router.go(qty);
return;
}
ignoreNavigations = Math.abs(qty) - 1;
router.go(qty);
};
The following code is used as the first line of route handlers:
if (ignoreNavigations-- > 0) return;
I did try simply setting a RouteEnabled flag to false when calling go(abs(qty)-1), before setting the flag back to true and calling a final go(-1), however it appears that response to the navigations occur asynchronously, and therefore I changed the implementation to the above code, rather than try and use timers and get all messy.

as3 non-explicit function pointer

Please see code below. I will have a bunch of elements, that I want to run whatever "formula" refers to, for that element. In the code, where it says, "this works", it works as expected. However I need to fire off these formulas, without naming "firstElement" explicitly. Even though the nested for loop is a little clunky, I think it should work, but it causes the error listed below. How can I fire off the formulas, without naming the elements explicitly? Thanks!
var test:Object = {
element:
[
{ "firstElement":
{
formula:myFunction
}
}
]
}// end test object
public function RunThisFunctionFirst() {
test.element[0].firstElement.formula();//this works
for (var index in test.element){
for (var object in test.element[index]){
trace ("object " + object);// traces "firstElement", as expected
object.formula()// this causes error: Error #1006: value is not a function.
}
}
}
function myFunction (){
trace ("my function called");
}
Using a for each loop you can simplify your loop, and as previously said don't forget to typed your variable :
for each (var elm:Object in test.element) {
for each (var obj:Object in elm) {
var formula:Function = obj.formula as Function
if (formula!=null) formula()
}
}
Your variable object, in (var object ... ) is not a typed variable. The compiler will default this to an Object class, which of course is not a Function class. Try casting object as a Function. I'm guess that you have extended myFunction from Function class.
either by:
for (var object:Function in test.element[index])
or
for (var object:myFunction ... ) // if myFunction is extended from Function
Regarding the outer loop, element is an array, not an object, so you want to use for(;;) not for in.
Regarding the inner loop, object is the string "firstElement" not an object.
for (var i:int=0; i < test.element.length; i++)
{
for (var key:* in test.element[i])
{
trace("key " + key);
var object:* = test.element[i][key];
trace("object " + object);
if(typeof object === "object" && object.hasOwnProperty("formula"))
object.formula();
}
}