node.js Number.prototype isn't behaving as expected - prototypejs

I'm trying to do a little math library to facilitate my app, this however is throwing an off error.
TypeError: Object 25 has no method 'permutation'
function permutate(p) {
var states = new Number(p.length)
chat( states.permutation(states) )
}
Number.prototype.factorial = function() {
for(var i = 2; i <= this; i++)
n*=i
return n
}
Number.prototype.permutation = function(r) {
return (this.factorial() / (this-r).factorial())
}
in addition to hopefully fixing my code, I'm really curious why the objects type is being interpreted as a number primitive? (or whatever is really going on here)

Related

jquery click function inside a for loop

I have this code. For some reason the 1st console.log prints out well in the console but the 2nd gives me an undefined when I click. The cvs array is global.
thanks for the help
var losotro = ['div.santiago', 'div.karina', 'div.roman', 'div.marcos'];
var cvs = ['div#cv0 p', 'div#cv1 p', 'div#cv2 p', 'div#cv3 p'];
for (i = 0; i < losotro.length; i++) {
console.log(cvs[i]);
jQuery(losotro[i]).click(function(){
console.log(cvs[i]);
});
}
This is a typical closure problem in JavaScript.
Basically, all the callback(the click event handlers) are referencing to the same variable i(I know, this is weird to me at first as well), which at the end of the loop should be losotro.length. And
absolutely this is out of the index range of the losotro array.
You may want to check how closure works in JavaScript. But for the current problem, you could do this.
var cvs = ['div#cv0 p', 'div#cv1 p', 'div#cv2 p', 'div#cv3 p'];
for (i = 0; i < losotro.length; i++) {
console.log(cvs[i]);
var bindedFunc = (function(i) {
return function() {
console.log(i)
}
})(i)
jQuery(losotro[i]).click(bindedFunc);
}

What are the performance differences between Promise.join Promise.all?

I was combing through the Bluebird docs, and they recommend using Promise.join over Promise.all for concurrent discrete promises.
The documentation says
Promise.join is much easier (and more performant) to use when you have a fixed amount of discrete promises that you want to coordinate concurrently.
However there's no explanation about the performance comment.
The only difference I see is that .all does the extra operation of unpacking the array. Seems like a stretch to call that "more performant" so maybe there's something else under the hood?
Any explanation would be helpful, thanks!
I have not seen any major performance impacts. Checkout the Fiddle here for benchmarking this:
https://jsfiddle.net/msmta/3936tnca/
// spread
function startSpreadTest() {
var startTime = new Date()
var spreadArray = []
for(var i = 0; i < promiseCount; i++)
spreadArray.push(Promise.delay(promiseDelay))
return Promise.all(spreadArray).spread(function(){
return getStopTime(startTime)
})
}
// join
function startJoinTest() {
var startTime = new Date()
var args = []
for(var i = 0; i < promiseCount; i++)
args.push(Promise.delay(promiseDelay))
args.push(function(){
return getStopTime(startTime)
})
return Promise.join.apply(null, args)
}

Creating a new kendo binding for "associative arrays"

I'll start off by stating that I don't know if this is possible at all, but I'm reading over the Kendo UI documentation and trying to figure out how to at least try it, but I'm running into a lot of difficulties with making a custom binding. This is a followup to another question I am still working on, which is posted here. If this is not an appropriate question, please kindly let me know, and I will close it or rephrase it. I'm just really lost and confused at this point.
As I understand it, based on what I've been told and tried, Kendo cannot bind to an Associative Array not because the data isn't good, but because it is an array of objects, each as a separate individual entity - under normal circumstances, an array would be a bit different and contain a length property, as well as some other functions in the array prototype that make iteration through it possible.
So I was trying to conjecture how to get around this. I succeeded in getting what I think was a workaround to function. I preface that with "think" because I'm still too inexperienced with Javascript to truly know the ramifications of doing it this way (performance, stability, etc)
Here is what I did;
kendo template
<script type="text/x-kendo-template" id="display-items-many">
# for(var key in data) { #
# if (data.hasOwnProperty(key) && data[key].hasOwnProperty("Id")) { #
<tr>
<td>
<strong>#= data[key].Id #</strong>
</td>
<td class="text-right">
<code>#= data[key].Total #</code>
</td>
</tr>
# } #
# } #
</script>
html
<table class="table borderless table-hover table-condensed" data-bind="source: Associative data-template="display-items-many">
</table>
Now to me, immediately off hand, this gave me the illusion of functioning. So I got to thinking a bit more on how to fix this ...
I want to create a new binding called repeat. The goal of this binding is as follows;
repeat the template for each instance of an object within the given root object that meets a given criteria
In my head, this would function like this;
<div data-template="repeater-sample" data-bind="repeat: Associative"></div>
<script type="text/x-kendo-template" id="repeater-sample">
<div> ${ data.Id }</div>
</script>
And the criteria would be a property simply called _associationKey. So the following would, in theory, work.
$.ajax({
// get data from server and such.
}).done(function(results){
// simple reference to the 'associative array' for easier to read code
var associative = results.AssociativeArray;
// this is a trait that everything in the 'associative array' should have to match
// this is purely, purely an example. Obviously you would use a more robust property
var match = "Id";
// go through the results and wire up the associative array objects
for(var key in associative ) {
if(associative.hasOwnProperty(key) && associative[key].hasOwnProperty(match)) {
associative[key]._associationKey = 10; // obviously an example value
}
}
// a watered down example implementation, obviously a real use would be more verbose
viewModel = kendo.observable({
// property = results.property
// property = results.property
associativeArray = associative
});
kendo.bind('body', viewModel);
});
So far this actually seems to work pretty well, but I have to hard code the logic in the template using inline scripting. That's kind of what I want to avoid.
Problem
The big issue is that I'm vastly confused on telerik's documentation for custom bindings (available here). I do have their examples to draw from, yes - but it's a bit confusing to me how it interacts with the object. I'll try to explain, but I'm so lost that it may be difficult.
This is what telerik gives for an example custom binding, and I've pruned it a bit for space concerns;
<script>
kendo.data.binders.repeater = kendo.data.Binder.extend({
init: function(element, bindings, options) {
//call the base constructor
kendo.data.Binder.fn.init.call(this, element, bindings, options);
var that = this;
// how do we interact with the data that was bound?
}
});
</script>
So essentially that's where I am lost. I'm having a big disconnect figuring out how to interact with the actual "associative array" that is bound using data-bind="repeat: associativeArray"
So ..
I need to interact with the bound data (the entire 'associative array')
I need to be able to tell it to render the target template for each instance that matches
Further Updates
I have been digging through the kendo source code, and this is what I have so far - by taking the source binding as an example... but I'm still not getting the right results. Unfortunately this poses a few problems;
some of the functions are internal to kendo, I'm not sure how to get access to them without re-writing them. While I have the source and can do that, I'd prefer to make version agnostic code so that it can "plug in" to newer releases
I'm totally lost about what a lot of this does. I basically made a copy of the source binding and replaced it with my own syntax where possible, since the concept is fundamentally the same. I cannot figure out where to do the test for qualification to be rendered, if that makes sense.
I'm having a big logic disconnect here - there should ideally be some place where I can basically say ... If the current item that kendo is attempting to render in a template matches a criteria, render it. If not, pass it over and then another place where I tell it to iterate over every object in the 'associative array' so as to get to the point where I test it.
I feel just forcing a for loop in here will actually make this fire too many times, and I am getting pretty lost. Any help is greatly appreciated.
kendo.data.binders.repeat = kendo.data.Binder.extend({
init: function(element, bindings, options) {
kendo.data.Binder.fn.init.call(this, element, bindings, options);
var source = this.bindings.repeat.get();
if (source instanceof kendo.data.DataSource && options.autoBind !== false) {
source.fetch();
}
},
refresh: function(e) {
var that = this,
source = that.bindings.repeat.get();
if (source instanceof kendo.data.ObservableArray|| source instanceof kendo.data.DataSource) {
e = e || {};
if (e.action == "add") {
that.add(e.index, e.items);
} else if (e.action == "remove") {
that.remove(e.index, e.items);
} else if (e.action != "itemchange") {
that.render();
}
} else {
that.render();
}
},
container: function() {
var element = this.element;
if (element.nodeName.toLowerCase() == "table") {
if (!element.tBodies[0]) {
element.appendChild(document.createElement("tbody"));
}
element = element.tBodies[0];
}
return element;
},
template: function() {
var options = this.options,
template = options.template,
nodeName = this.container().nodeName.toLowerCase();
if (!template) {
if (nodeName == "select") {
if (options.valueField || options.textField) {
template = kendo.format('<option value="#:{0}#">#:{1}#</option>',
options.valueField || options.textField, options.textField || options.valueField);
} else {
template = "<option>#:data#</option>";
}
} else if (nodeName == "tbody") {
template = "<tr><td>#:data#</td></tr>";
} else if (nodeName == "ul" || nodeName == "ol") {
template = "<li>#:data#</li>";
} else {
template = "#:data#";
}
template = kendo.template(template);
}
return template;
},
add: function(index, items) {
var element = this.container(),
parents,
idx,
length,
child,
clone = element.cloneNode(false),
reference = element.children[index];
$(clone).html(kendo.render(this.template(), items));
if (clone.children.length) {
parents = this.bindings.repeat._parents();
for (idx = 0, length = items.length; idx < length; idx++) {
child = clone.children[0];
element.insertBefore(child, reference || null);
bindElement(child, items[idx], this.options.roles, [items[idx]].concat(parents));
}
}
},
remove: function(index, items) {
var idx, element = this.container();
for (idx = 0; idx < items.length; idx++) {
var child = element.children[index];
unbindElementTree(child);
element.removeChild(child);
}
},
render: function() {
var source = this.bindings.repeat.get(),
parents,
idx,
length,
element = this.container(),
template = this.template();
if (source instanceof kendo.data.DataSource) {
source = source.view();
}
if (!(source instanceof kendo.data.ObservableArray) && toString.call(source) !== "[object Array]") {
source = [source];
}
if (this.bindings.template) {
unbindElementChildren(element);
$(element).html(this.bindings.template.render(source));
if (element.children.length) {
parents = this.bindings.repeat._parents();
for (idx = 0, length = source.length; idx < length; idx++) {
bindElement(element.children[idx], source[idx], this.options.roles, [source[idx]].concat(parents));
}
}
}
else {
$(element).html(kendo.render(template, source));
}
}
});
I would propose as a simpler solution transform transmitted associative array in an array. This is pretty simple and (for most cases) can solve your problem.
Lets say that you get the following associative array received from the server:
{
"One" : { Name: "One", Id: "id/one" },
"Two" : { Name: "Two", Id: "id/two" },
"Three" : { Name: "Three", Id: "id/three" }
}
That is store in a variable called input. Transform it from associative to no associative is as easy as:
var output = [];
$.each(input, function(idx, elem) {
elem.index = idx;
output.push(elem);
});
Now, you have in output an equivalent array where I saved the index field into a field called index for each element of the associative array.
Now you can use out-of-the-box code for displaying the data received from the server.
See it in action here : http://jsfiddle.net/OnaBai/AGfWc/
You can even use KendoUI DataSource for retrieving and transforming the data by using DataSource.schema.parse method as:
var dataSource = new kendo.data.DataSource({
transport: {
read: ...
},
schema : {
parse: function (response) {
var output = [];
$.each(response, function(idx, elem) {
elem.index = idx;
output.push(elem);
});
return output;
}
}
});
and your model would be:
var viewModel = new kendo.data.ObservableObject({
Id: "test/id",
Associative: dataSource
});
You can see it in action here: http://jsfiddle.net/OnaBai/AGfWc/1/

ObjectSave causes java.io.UTFDataFormatException

Raised as bug with Railo https://issues.jboss.org/browse/RAILO-2698 - this question should be closed
I am currently attempting to ObjectSave() on a rather complex Struct which contains instances of some CFCs among other data using the following cfscript (this is a test script I put together to reproduce the issue)
<cfscript>
thisState = session.objBasket.getState();
writedump(thisState); // dumps the object successfully
ObjectSave(thisState); // causes java.io.UTFDataFormatException
</cfscript>
I am getting the following error java.io.UTFDataFormatException (stack trace follows). Does anyone know of a way to fix this, or is it a matter of simply trying to use the wrong tool for the job?
Railo versions the error occurs on
Railo 4.1.1.009 final (Java 1.7.0_45)
Railo 4.1.1.009 final (Java 1.7.0_17)
Railo 4.1.2.001 final (Java 1.7.0_45) (Preview release)
Railo versions the error does not occur on
Railo 4.0.4.001 final (Java 1.7.0_45)
Stack trace of the error
java.io.UTFDataFormatException at
java.io.ObjectOutputStream$BlockDataOutputStream.writeUTF(ObjectOutputStream.java:2163):2163
at
java.io.ObjectOutputStream$BlockDataOutputStream.writeUTF(ObjectOutputStream.java:2006):2006
at
java.io.ObjectOutputStream.writeUTF(ObjectOutputStream.java:868):868
at
railo.runtime.ComponentImpl.writeExternal(ComponentImpl.java:1975):1975
at
java.io.ObjectOutputStream.writeExternalData(ObjectOutputStream.java:1458):1458
at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429):1429
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177):1177
at
java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347):347
at java.util.HashMap.writeObject(HashMap.java:1133):1133 at
sun.reflect.GeneratedMethodAccessor62.invoke(Unknown Source):-1 at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43):43
at java.lang.reflect.Method.invoke(Method.java:606):606 at
java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988):988
at
java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1495):1495
at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431):1431
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177):1177
at
java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347):347
at
railo.commons.collection.AbstractMapPro.writeExternal(AbstractMapPro.java:49):49
at
java.io.ObjectOutputStream.writeExternalData(ObjectOutputStream.java:1458):1458
at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429):1429
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177):1177
at
java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547):1547
at
java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508):1508
at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431):1431
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177):1177
at
java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347):347
at java.util.HashMap.writeObject(HashMap.java:1133):1133 at
sun.reflect.GeneratedMethodAccessor62.invoke(Unknown Source):-1 at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43):43
at java.lang.reflect.Method.invoke(Method.java:606):606 at
java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988):988
at
java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1495):1495
at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431):1431
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177):1177
at
java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347):347
at
railo.commons.collection.AbstractMapPro.writeExternal(AbstractMapPro.java:49):49
at
java.io.ObjectOutputStream.writeExternalData(ObjectOutputStream.java:1458):1458
at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429):1429
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177):1177
at
java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547):1547
at
java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508):1508
at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431):1431
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177):1177
at
java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347):347
at
railo.runtime.converter.JavaConverter.serialize(JavaConverter.java:67):67
at
railo.runtime.functions.other.ObjectSave.call(ObjectSave.java:31):31
at
railo.runtime.functions.other.ObjectSave.call(ObjectSave.java:22):22
at
mso.clientobject_cfc$cf._3(/var/www/html/www/www.simon.test/mso/ClientObject.cfc:476):476
at
mso.clientobject_cfc$cf.udfCall(/var/www/html/www/www.simon.test/mso/ClientObject.cfc):-1
at railo.runtime.type.UDFImpl.implementation(UDFImpl.java:94):94 at
railo.runtime.type.UDFImpl._call(UDFImpl.java:307):307 at
railo.runtime.type.UDFImpl.callWithNamedValues(UDFImpl.java:198):198
at
railo.runtime.type.scope.UndefinedImpl.callWithNamedValues(UndefinedImpl.java:709):709
at
railo.runtime.util.VariableUtilImpl.callFunctionWithNamedValues(VariableUtilImpl.java:738):738
at
railo.runtime.PageContextImpl.getFunctionWithNamedValues(PageContextImpl.java:1513):1513
at
mso.clientobject_cfc$cf._3(/var/www/html/www/www.simon.test/mso/ClientObject.cfc:437):437
at
mso.clientobject_cfc$cf.udfCall(/var/www/html/www/www.simon.test/mso/ClientObject.cfc):-1
at railo.runtime.type.UDFImpl.implementation(UDFImpl.java:94):94 at
railo.runtime.type.UDFImpl._call(UDFImpl.java:307):307 at
railo.runtime.type.UDFImpl.callWithNamedValues(UDFImpl.java:198):198
at railo.runtime.ComponentImpl._call(ComponentImpl.java:617):617 at
railo.runtime.ComponentImpl._call(ComponentImpl.java:499):499 at
railo.runtime.ComponentImpl.callWithNamedValues(ComponentImpl.java:1732):1732
at
railo.runtime.util.VariableUtilImpl.callFunctionWithNamedValues(VariableUtilImpl.java:738):738
at
railo.runtime.PageContextImpl.getFunctionWithNamedValues(PageContextImpl.java:1513):1513
at
mso.proxyclientobject_cfm$cf._1(/var/www/html/www/www.simon.test/mso/proxyClientObject.cfm:19):19
at
mso.proxyclientobject_cfm$cf.udfCall(/var/www/html/www/www.simon.test/mso/proxyClientObject.cfm):-1
at railo.runtime.type.UDFImpl.implementation(UDFImpl.java:94):94 at
railo.runtime.type.UDFImpl._call(UDFImpl.java:307):307 at
railo.runtime.type.UDFImpl.call(UDFImpl.java:211):211 at
railo.runtime.ComponentImpl._call(ComponentImpl.java:616):616 at
railo.runtime.ComponentImpl._call(ComponentImpl.java:499):499 at
railo.runtime.ComponentImpl.call(ComponentImpl.java:1715):1715 at
railo.runtime.util.VariableUtilImpl.callFunctionWithoutNamedValues(VariableUtilImpl.java:712):712
at
railo.runtime.PageContextImpl.getFunction(PageContextImpl.java:1503):1503
at
preparecosting_cfm$cf.call(/var/www/html/www/www.simon.test/prepareCosting.cfm:24):24
at
railo.runtime.PageContextImpl.doInclude(PageContextImpl.java:834):834
at
railo.runtime.PageContextImpl.doInclude(PageContextImpl.java:781):781
at
application_cfc$cf._1(/var/www/html/www/www.simon.test/Application.cfc:177):177
at
application_cfc$cf.udfCall(/var/www/html/www/www.simon.test/Application.cfc):-1
at railo.runtime.type.UDFImpl.implementation(UDFImpl.java:94):94 at
railo.runtime.type.UDFImpl._call(UDFImpl.java:307):307 at
railo.runtime.type.UDFImpl.call(UDFImpl.java:211):211 at
railo.runtime.ComponentImpl._call(ComponentImpl.java:616):616 at
railo.runtime.ComponentImpl._call(ComponentImpl.java:499):499 at
railo.runtime.ComponentImpl.call(ComponentImpl.java:1715):1715 at
railo.runtime.listener.ModernAppListener.call(ModernAppListener.java:388):388
at
railo.runtime.listener.ModernAppListener._onRequest(ModernAppListener.java:204):204
at
railo.runtime.listener.MixedAppListener.onRequest(MixedAppListener.java:18):18
at
railo.runtime.PageContextImpl.execute(PageContextImpl.java:2167):2167
at
railo.runtime.PageContextImpl.execute(PageContextImpl.java:2134):2134
at
railo.runtime.engine.CFMLEngineImpl.serviceCFML(CFMLEngineImpl.java:335):335
at railo.loader.servlet.CFMLServlet.service(CFMLServlet.java:29):29 at
javax.servlet.http.HttpServlet.service(HttpServlet.java:728):728 at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305):305
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210):210
at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222):222
at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123):123
at
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472):472
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171):171
at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99):99
at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118):118
at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407):407
at
org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:200):200
at
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589):589
at
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310):310
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145):1145
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615):615
at java.lang.Thread.run(Thread.java:744):744
Unit test + accompanying cfc that can be used to reproduce
javaErrorTest.cfc (Unit test)
component extends='mxunit.framework.TestCase' {
public void function trySavingLargeNestedStruct() {
// Prove that it doesn't happen with nested structures
var nestedStruct = {};
var nestInMe = nestedStruct;
// Make a big struct
var nestedStruct = {};
var v = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
for (var i in v) {
for (var j in v) {
for (var k in v) {
for (var l in v) {
nestedStruct[i][j][k][l] = {};
}
}
}
}
debug('Nested struct len = '&len(serialize(nestedStruct)));
ObjectSave(nestedStruct);
debug('Nested struct saved without error');
}
public void function triggerUTFDataFormatException() {
// Prove that it happens with objects nested deeply
var previousLength = 0;
for (var i=600;i<700;i++) {
objTest = new TestObject( levels = i );
var strSerialized = serialize(objTest);
try {
ObjectSave(objTest);
} catch (java.io.UTFDataFormatException e) {
// Expected place of java.io.UTFDataFormatException
debug('Levels = '&i-1&' has serialize() length = '&previousLength);
debug('Levels = '&i&' has serialize() length = '&Len(strSerialized));
debug(strSerialized);
debug(e);
fail('java.io.UTFDataFormatException (expected) error thrown');
} catch (any e) {
debug(e);
fail('Error thrown, not not the expected one');
}
previousLength = Len(strSerialized);
}
}
}
TestObject.cfc (Used within the failing test)
component {
public TestObject function init(
required numeric levels = 0
) {
variables.a = (arguments.levels > 0)?new TestObject( levels = arguments.levels - 1 ):{};
return this;
}
}
Look at the stack trace. It answers all your questions.
java.io.UTFDataFormatException at java.io.ObjectOutputStream$BlockDataOutputStream.writeUTF(ObjectOutputStream.java:2163):2163 at java.io.ObjectOutputStream$BlockDataOutputStream.writeUTF(ObjectOutputStream.java:2006):2006
A glance at the Javadoc shows that this exception is thrown by writeUTF() if the data to be written is longer than 65535 bytes.
railo.runtime.ComponentImpl.writeExternal(ComponentImpl.java:1975):1975
This is the code that calls writeUTF(). So it appears to be a bug in the railo.runtime.ComponentImpl class. It shouldn't be calling writeUTF() for such a long string.
The following 2 methods are what I am using in place of ObjectSave and ObjectLoad until the Railo bug is corrected. It seems to function up to a decent level of complexity.
// Replaces ObjectSave
private binary function serializeState(
required struct inState
) {
var strSerialized = serialize(arguments.inState);
return strSerialized.GetBytes();
}
// Replaces ObjectLoad
private struct function deserializeState(
required binary inState
) {
var strSerialized = ToString(arguments.inState);
var stcDeserialized = evaluate(strSerialized);
return stcDeserialized;
}

facing performance issues with knockout mapping plugin

I have decent large data set of around 1100 records. This data set is mapped to an observable array which is then bound to a view. Since these records are updated frequently, the observable array is updated every time using the ko.mapping.fromJS helper.
This particular command takes around 40s to process all the rows. The user interface just locks for that period of time.
Here is the code -
var transactionList = ko.mapping.fromJS([]);
//Getting the latest transactions which are around 1100 in number;
var data = storage.transactions();
//Mapping the data to the observable array, which takes around 40s
ko.mapping.fromJS(data,transactionList)
Is there a workaround for this? Or should I just opt of web workers to improve performances?
Knockout.viewmodel is a replacement for knockout.mapping that is significantly faster at creating viewmodels for large object arrays like this. You should notice a significant performance increase.
http://coderenaissance.github.com/knockout.viewmodel/
I have also thought of a workaround as follows, this uses less amount of code-
var transactionList = ko.mapping.fromJS([]);
//Getting the latest transactions which are around 1100 in number;
var data = storage.transactions();
//Mapping the data to the observable array, which takes around 40s
// Instead of - ko.mapping.fromJS(data,transactionList)
var i = 0;
//clear the list completely first
transactionList.destroyAll();
//Set an interval of 0 and keep pushing the content to the list one by one.
var interval = setInterval(function () {if (i == data.length - 1 ) {
clearInterval(interval);}
transactionList.push(ko.mapping.fromJS(data[i++]));
}, 0);
I had the same problem with mapping plugin. Knockout team says that mapping plugin is not intended to work with large arrays. If you have to load such big data to the page then likely you have improper design of the system.
The best way to fix this is to use server pagination instead of loading all the data on page load. If you don't want to change design of your application there are some workarounds which maybe help you:
Map your array manually:
var data = storage.transactions();
var mappedData = ko.utils.arrayMap(data , function(item){
return ko.mapping.fromJS(item);
});
var transactionList = ko.observableArray(mappedData);
Map array asynchronously. I have written a function that processes array by portions in another thread and reports progress to the user:
function processArrayAsync(array, itemFunc, afterStepFunc, finishFunc) {
var itemsPerStep = 20;
var processor = new function () {
var self = this;
self.array = array;
self.processedCount = 0;
self.itemFunc = itemFunc;
self.afterStepFunc = afterStepFunc;
self.finishFunc = finishFunc;
self.step = function () {
var tillCount = Math.min(self.processedCount + itemsPerStep, self.array.length);
for (; self.processedCount < tillCount; self.processedCount++) {
self.itemFunc(self.array[self.processedCount], self.processedCount);
}
self.afterStepFunc(self.processedCount);
if (self.processedCount < self.array.length - 1)
setTimeout(self.step, 1);
else
self.finishFunc();
};
};
processor.step();
};
Your code:
var data = storage.transactions();
var transactionList = ko.observableArray([]);
processArrayAsync(data,
function (item) { // Step function
var transaction = ko.mapping.fromJS(item);
transactionList().push(transaction);
},
function (processedCount) {
var percent = Math.ceil(processedCount * 100 / data.length);
// Show progress to the user.
ShowMessage(percent);
},
function () { // Final function
// This function will fire when all data are mapped. Do some work (i.e. Apply bindings).
});
Also you can try alternative mapping library: knockout.wrap. It should be faster than mapping plugin.
I have chosen the second option.
Mapping is not magic. In most of the cases this simple recursive function can be sufficient:
function MyMapJS(a_what, a_path)
{
a_path = a_path || [];
if (a_what != null && a_what.constructor == Object)
{
var result = {};
for (var key in a_what)
result[key] = MyMapJS(a_what[key], a_path.concat(key));
return result;
}
if (a_what != null && a_what.constructor == Array)
{
var result = ko.observableArray();
for (var index in a_what)
result.push(MyMapJS(a_what[index], a_path.concat(index)));
return result;
}
// Write your condition here:
switch (a_path[a_path.length-1])
{
case 'mapThisProperty':
case 'andAlsoThisOne':
result = ko.observable(a_what);
break;
default:
result = a_what;
break;
}
return result;
}
The code above makes observables from the mapThisProperty and andAlsoThisOne properties at any level of the object hierarchy; other properties are left constant. You can express more complex conditions using a_path.length for the level (depth) the value is at, or using more elements of a_path. For example:
if (a_path.length >= 2
&& a_path[a_path.length-1] == 'mapThisProperty'
&& a_path[a_path.length-2] == 'insideThisProperty')
result = ko.observable(a_what);
You can use typeOf a_what in the condition, e.g. to make all strings observable.
You can ignore some properties, and insert new ones at certain levels.
Or, you can even omit a_path. Etc.
The advantages are:
Customizable (more easily than knockout.mapping).
Short enough to copy-paste it and write individual mappings for different objects if needed.
Smaller code, knockout.mapping-latest.js is not included into your page.
Should be faster as it does only what is absolutely necessary.

Resources