Sample
Please consider this Plunk.
Background
The Plunk is a seriously simplified sample of what I need to do. Basically I need to get a person record with validation result included. This result will also include class information, so that the controller can assign proper styling to indicate mandatory status (or not).
The issue
The most important function in the sample is this one, the self.Get will use the validation logic and result a result.
self.Get('0f8fad5b-d9cb-469f-a165-70867728950e').then(function(result){
$scope.person = result.person;
$scope.validationResult = result.ValidateResult;
});
As you can see (because the form has correct values) $scope.person is loaded correctly, the $scope.validationResult however is not.
The question
I suspect there's a timing issue with the consecutive async calls, how can I fix this Plunk so that everything works correctly?
Nesting async calls in each other would be 'one' solution, I guess, but given the number of calls being made, that would not solve everything and the code would become highly unreadable.
For multiple async calls I would suggest to use array of promises:
var promises = [];
promises.push(service1.get(...))
promises.push(service2.get(...))
promises.push(service3.get(...))
return $q.all(promises);
So, how do I convert the following code to use chaining, while keeping all dependencies intact?:
self.Get = function (personId) {
// 1. Init
var defer = $q.defer();
var asyncCallsResult = {};
// 2. Get person
var person = self.GetTestPerson();
asyncCallsResult.person = person;
self.LoadPersonDetailProxy(person).then(function(personDetailProxy) {
$scope.personDetailProxy = personDetailProxy;
});
validationService.ValidateAsync($scope.personDetailProxy).then(function (validateResult) {
asyncCallsResult.ValidateResult = validateResult;
});
defer.resolve(asyncCallsResult);
return defer.promise;
}
Related
I'm using a library (playcanvas) that exposes a function clone() that is called recursively for all the nodes in a hierarchy.
If I monkey patch the function to execute some additional code, this will be executed multiple times.
Instead, I need to execute my code at the end of the whole recursive calls, but I can't find a way to do it.
pc.Entity.prototype.clone = function() {
... some code
// then for each child it calls itself
}
If I try this way I get "my stuff" executed multiple times.
pc.Entity.prototype.cloneOriginal = pc.Entity.prototype.clone;
pc.Entity.prototype.clone = function() {
var c = this.cloneOriginal();
// do my stuff
return c;
}
I need to "override" the clone method so that after all its recursive calls, I can execute my code.
You can achieve that by temporarily restoring the original function before launching it. And when it is finished, you set your trap again, and perform your post processing:
const orig_clone = pc.Entity.prototype.clone; // Save original clone
// Set trap:
pc.Entity.prototype.clone = function patched_clone(...args) {
pc.Entity.prototype.clone = orig_clone; // Restore original function
let result = this.clone(...args); // Execute it
// All is done, including recursion.
pc.Entity.prototype.clone = patched_clone; // Set trap again
// Your code comes here
console.log('post processing');
return result;
}
I'd still go with a simple flag to determine wether I'm inside a recursion or not.
//no need to store that function on the prototype itself
const cloneOriginal = pc.Entity.prototype.clone;
let inRecursion = false;
pc.Entity.prototype.clone = function() {
//just pass through the call to the original function.
if(inRecursion)
return cloneOriginal.call(this);
inRecursion = true;
var c = cloneOriginal.call(this);
inRecursion = false;
// do my stuff
return c;
}
inRecursion is a flag, specific for this single implementation. Maybe you want to wrap this code in a block or an iife to ensure that the variables are not accessible from outside of your clone-method.
could you point me to some more info about the optimization you are speaking about. What should I google?
You'll find most about v8 optimizations on google, but most modern browsers do similar stuff. I just googled and came across this article Performance Tips for JavaScript in V8. It's a bit older, but I think it's a good point to start getting an understanding on the kind of optimizations that JS engines do to your code to make it faster.
But as the article it mentions, don't loose yourself in (pointless) optimizations.
Premise: JS ES6, NodeJS
Testing Framework: TAP
Mocking Library: testdouble.js
I am attempting to mock the return value for the method of my class and keep receiving this error:
not ok Unsatisfied verification on test double. Wanted: - called with (true). But there were no invocations of the test double.
Here is my testing code:
// Imports for unit testing
const tap = require('tap');
const Subject = require('../src/iTunesClient.js');
const td = require('testdouble');
let reqJson;
// Ensure the iTunes class methods are called
tap.test('iTunesClient class methods function as intended', (t) => {
t.beforeEach((ready) => {
reqJson = td.replace('../src/reqJson.js');
ready();
});
t.afterEach((ready) => {
td.reset();
ready();
});
t.test('iTunesClient.getData', (assert) => {
const callback = td.function();
const subject = new Subject();
subject.setTerm('abc 123');
subject.setURL();
td.when(reqJson.get(td.callback)).thenCallback(true);
subject.getData(callback);
td.verify(callback(true));
assert.end();
});
t.end();
});
Specifically, this line is related to my issue:
td.verify(callback(true));
How can I fake the callback value of true for reqJson.get()? Right now, Subject.geData() is a method of the iTunesClient class which calls another file, reqJson.js, to use its exported get() method.
It's a little hard to tell from your example, but it looks like you're requiring iTunesClient before you call td.replace. In this case, the real reqJson module will be required and cached on line 3.
You need to call td.replace early enough to avoid this, e.g. in between requiring tap and iTunesClient.
I wanted to update this question, as I recently solved this issue. Essentially, I had two issues:
Account for both reqJson function parameters
Account for all callback return values
Per testdouble documentation for item 1:
When passed td.matchers.anything(), any invocation of that test double function will ignore that parameter when determining whether an invocation satisfies the stubbing.
Hence, I adjusted my line of code as follows:
Before: td.when(reqJson.get(td.callback)).thenCallback(true);
After: td.when(reqJson.get(td.matchers.anything(), td.callback)).thenCallback(null, null, null);
Ok, I wouldn't think to do this in C#, but javascript is designed with much more flexibility in access.
there's a plugin like this
(function($)
{
...more stuff
var results={a:1,b:2} //this I need to modify
var someData={x:1}
send = function(){
//send results ajax
};
if(typeof beforeSend=='function')
beforeSend(someData) //hook to use results
})(jQuery)
So, in my own code, I have the function window.beforeSend = function(d){}
and it does have the someData which is in the scope I need to modify. But here's the question:
How can I modify the results var that's within the closure before it sends it.
I need to add
window.beforeSend = function(d){
window.quantumTunnelThroughScope.results['c']=1
}
The reason I need to do this is because I cannot modify the code of the plugin. Of course if I add the beforeSend within the closure, it works, but then I'm modifying the library which I'm not allowed to do in this case.
I've seen some awesome eval('this.xx' =function ) etc etc but I can't make it work.
EDIT: I clarified that actually it's a different var in the same scope that needs to be edited
No, there's no reasonable way for beforeSend to reach into that closure and modify results. results in the code presented is entirely private to code within that closure.
The unreasonable way to try to do it is to decompile and recompile the plugin function, via eval, and insert a call to a function before the beforeSend that lets us modify results:
(function($) {
$.run = function() {
// You mentioned "ajax," so let's make this
// asynchronous
setTimeout(function() {
var results = {
a: 1,
b: 2
};
var someData = { // Need to modify this
x: 1
};
send = function() {
//send results ajax
};
if (typeof beforeSend == 'function') {
beforeSend(someData); //hook to use results
}
console.log("in plugin, results = ", results);
}, 10);
};
})(jQuery)
window.modifyResults = function(d) {
return ["new", "results"];
};
window.beforeSend = function(r) {
r.c = 1;
};
jQuery.run = (function() {
// Function#toString, on nearly all browsers, returns the source
// code of he function (or something near to it) except on functions
// implemented in native code. We take that string and replace
// the "beforeSend(someData);" call with two calls, the first of
// which lets us modify the `results` variable. Then we use eval
// to turn that back into a function, and assign the result to
// where the plugin put its function originally.
return eval("(" + jQuery.run.toString().replace(
"beforeSend(someData);",
"results = modifyResults(results); beforeSend(someData);"
) + ")");
})();
jQuery.run();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
But may or may not work, depending on how the plugin is written, as it lifts it out of its original scope and recompiles it in the scope of our function updating jQuery.run.
I think I'd prefer to take the hit of modifying the plugin. :-)
Note: In the above, I've used a "static" jQuery function. If the plugin you're replacing provides an instance function, the kind you can call on jQuery instances, e.g. the bar in $(".foo").bar(), you'll find it on jQuery.fn instead of jQuery:
jQuery.fn.pluginFunction = eval(...);
I am creating a webapp with dynamic TABs (data from RESTful) and each TAB has a dgrid, which I get the columns from a RESTful and the rows from a RESTful, as well. I made everything works well with XHR and MemoryStore, but I now need to change from XHR to JsonRest, because I need to pass to the server, a HTTP Range.
I am having dificulties to organize my code with Asynchronous calls in Dojo. I will give you an example:
method1() - Sync
method2() - Async (JsonRest)
method3() - Sync
What the best way for the method3() be executed, only after method2() is ready?
I have found a class called WHEN. It seems nice. But how do you work with Async apps in dojo?
My biggest problem now: I can't separate my codes by methods, I need put all my code inside the JsonRest's promise function(THEN). Because inside THEN I can't access another method.
I would concur with the recommendation of using Dojo's promise implementation.
This might help you make some sense of it faster if you are not used to promises: http://jsfiddle.net/27jyf/9/. Another nice feature of this is error handling, I would encourage you to read on this after you have the basic sequencing down.
require(["dojo/Deferred", "dojo/when"], function(Deferred, when) {
var sayHello = function() { return 'hello' };
var sayWorld = function() {
var deferred = new Deferred();
window.setTimeout(function() {
deferred.resolve('world');
}, 1000);
return deferred.promise;
};
var sayBang = function() { return '!' };
//This will echo 'hello world !'
//That's probably how you want to sequence your methods here
var message = [];
message.push(sayHello());
sayWorld().then(function(part) {
message.push(part);
message.push(sayBang());
console.debug(message.join(' '));
});
//This will also echo 'hello world !'
//This probably not the syntax that you want here,
//but it shows how to sequence promises and what 'when' actually does
var message2 = [];
when(sayHello())
.then(function(part) {
message2.push(part);
return sayWorld();
})
.then(function(part) {
message2.push(part);
return when(sayBang());
})
.then(function(part) {
message2.push(part);
console.debug(message2.join(' '));
});
//Provided the behavior observed above, this will echo 'hello !'
//dojo/when allows you to use the same syntax for sync and async...
//but it does not let you magically write async operations in a sync syntax
//'world' will be pushed into the array a second later, after the message has already been echoed
var message3 = [];
message3.push(sayHello());
when(sayWorld(), function(part) {
message3.push(part);
});
message3.push(sayBang());
console.debug(message3.join(' '));
});
You can use the promise api to run async/sync methods in a specified order.
Just by seeing what I've wrote now, I can see that one is much smaller, so in terms of code golf Option 2 is the better bet, but as far as which is cleaner, I prefer Option 1. I would really love the community's input on this.
Option 1
something_async({
success: function(data) {
console.log(data);
},
error: function(error) {
console.log(error);
}
});
Option 2
something_async(function(error,data){
if(error){
console.log(error);
}else{
console.log(data);
}
});
They are not exactly the same. Option 2 will still log the (data), whereas Option 1 will only log data on success. (Edit: At least it was that way before you changed the code)
That said, Option 1 is more readable. Programming is not / should not be a competition to see who can write the fewest lines that do the most things. The goal should always be to create maintainable, extendable (if necessary) code --- in my humble opinion.
Many people will find option#1 easier to read and to maintain - two different callback functions for two different purposes. It is commonly used by all Promise Libraries, where two arguments will be passed. Of course, the question Multiple arguments vs. options object is independent from that (while the object is useful in jQuery.ajax, it doesn't make sense for promise.then).
However, option#2 is Node.js convention (see also NodeGuide) and used in many libraries that are influenced by it, for example famous async.js. However, this convention is discussable, top google results I found are WekeRoad: NodeJS Callback Conventions and Stackoverflow: What is the suggested callback style for Node.js libraries?.
The reason for the single callback function with an error argument is that it always reminds the developer to handle errors, which is especially important in serverside applications. Many beginners at clientside ajax functions don't care forget about error handling for example, asking themselves why the success callback doesn't get invoked. On the other hand, promises with then-chaining are based on the optionality of error callbacks, propagating them to the next level - of course it still needs to be catched there.
In all honesty, I prefer to take them one step further, into Promises/Futures/Deferreds/etc...
Or (/and) go into a "custom event" queue, using a Moderator (or an observer/sub-pub, if there is good reason for one particular object to be the source for data).
This isn't a 100% percent of the time thing. Sometimes, you just need a single callback. However, if you have multiple views which need to react to a change (in model data, or to visualize user-interaction), then a single callback with a bunch of hard-coded results isn't appropriate.
moderator.listen("my-model:timeline_update", myView.update);
moderator.listen("ui:data_request", myModel.request);
button.onclick = function () { moderator.notify("ui:data_request", button.value); }
Things are now much less dependent upon one big callback and you can mix and match and reuse code.
If you want to hide the moderator, you can make it a part of your objects:
var A = function () {
var sys = null,
notify = function (msg, data) {
if (sys && sys.notify) { sys.notify(msg, data); }
},
listen = function (msg, callback) {
if (sys && sys.listen) { sys.listen(msg, callback); }
},
attach = function (messenger) { sys = messenger; };
return {
attach : attach
/* ... */
};
},
B = function () { /* ... */ },
shell = Moderator(),
a = A(),
b = B();
a.attach(shell);
b.attach(shell);
a.listen("do something", a.method.bind(a));
b.notify("do something", b.property);
If this looks a little familiar, it's similar behaviour to, say Backbone.js (except that they extend() the behaviour onto objects, and others will bind, where my example has simplified wrappers to show what's going on).
Promises would be the other big-win for usability, maintainable and easy to read code (as long as people know what a "promise" is -- basically it passes around an object which has the callback subscriptions).
// using jQuery's "Deferred"
var ImageLoader = function () {
var cache = {},
public_function = function (url) {
if (cache[url]) { return cache[url].promise(); }
var img = new Image(),
loading = $.Deferred(),
promise = loading.promise();
img.onload = function () { loading.resolve(img); };
img.onerror = function () { loading.reject("error"); };
img.src = url;
cache[url] = loading;
return promise;
};
return public_function;
};
// returns promises
var loadImage = ImageLoader(),
myImg = loadImage("//site.com/img.jpg");
myImg.done( lightbox.showImg );
myImg.done( function (img) { console.log(img.width); } );
Or
var blog_comments = [ /* ... */ ],
comments = BlogComments();
blog_comments.forEach(function (comment) {
var el = makeComment(comment.author, comment.text),
img = loadImage(comment.img);
img.done(el.showAvatar);
comments.add(el);
});
All of the cruft there is to show how powerful promises can be.
Look at the .forEach call there.
I'm using Image loading instead of AJAX, because it might seem a little more obvious in this case:
I can load hundreds of blog comments, if the same user makes multiple posts, the image is cached, and if not, I don't have to wait for images to load, or write nested callbacks. Images load in any order, but still appear in the right spots.
This is 100% applicable to AJAX calls, as well.
Promises have proven to be the way to go as far as async and libraries like bluebird embrace node-style callbacks (using the (err, value) signature). So it seems beneficial to utilize node-style callbacks.
But the examples in the question can be easily be converted into either format with the functions below. (untested)
function mapToNodeStyleCallback(callback) {
return {
success: function(data) {
return callback(null, data)
},
error: function(error) {
return callback(error)
}
}
}
function alterNodeStyleCallback(propertyFuncs) {
return function () {
var args = Array.prototype.slice.call(arguments)
var err = args.shift()
if (err) return propertyFuncs.err.apply(null, [err])
return propertyFuncs.success.apply(null, args)
}
}