I want to write a javascript function that can flexibly add parameter. For detail, I want to encapsulate the singalR invoke function like below, but how should handle the parameter? e.g. I want to call like this var proxy = initSignalr();
proxy.invoke('Login',name, pw, fn), how should I adjust below code so I can make it flexible to add parameters.(e.g. maybe I also need to call proxy.invoke('sendMessage',message, fn) )
function initSignalr(){
var connection = $.hubConnection('http://xxxxxxx');
var proxy = connection.createHubProxy('xxxxxxx');
connection.start().done(function(){
console.log("signalr connected");
});
return {
on: function (eventName, callback) {
proxy.on(eventName, function (result) {
$rootScope.$apply(function () {
if (callback) {
callback(result);
}
});
});
},
invoke: function (methodName, callback) {
proxy.invoke(methodName)
.done(function (result) {
$rootScope.$apply(function () {
if (callback) {
callback(result);
}
});
});
}
};}
function test() {
for(var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
test();
test('Some Text String');
test(5, 6, function() { console.log('test') })
Related
I have a variable oldBindings which record all the existing bindings of an Excel table. I have built BindingDataChanged listeners based on oldBindings. So when newBindings come up, I need to remove all the old listeners linked to oldBindings and add new listeners based on newBindings. At the moment, I have written the following code:
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings, function () {
addEventHandlers(newBindings)
})
}
function removeEventHandlers(oldBindings, cb) {
for (var i = 0; i < oldBindings.length; i++) {
Office.select("binding#"+oldBindings[i]).removeHandlerAsync(Office.EventType.BindingDataChanged, function (asyncResult) {
Office.context.document.bindings.releaseByIdAsync(oldBindings[i], function () {});
});
}
cb()
}
As removeHandlerAsync and releaseByIdAsync are built with callback rather than promise, I need to organise the whole code with callback. There are 2 things I am not sure:
1) in removeEventHandlers, will cb() ALWAYS be executed after the removal of all the listeners? How could I ensure that?
2) Do I have to make addEventHandlers as a callback of removeEventHandlers to ensure their execution order?
1) in removeEventHandlers, will cb() ALWAYS be executed after the removal of all the listeners?
No. It'll be called after the initiation of the removal. But if the removal is async, it may be called before the removal is complete.
2) Do I have to make addEventHandlers as a callback of removeEventHandlers to ensure their execution order?
Yes, but not the way you have. The way you have is just like doing
removeEventHandlers();
addEventHandlers();
because you call cb at the end of removeEventHandlers without waiting for anything to finish.
As removeHandlerAsync and releaseByIdAsync are built with callback rather than promise, I need to organise the whole code with callback.
Or you could give yourself Promise versions of them. More on that in a moment.
Using the non-Promise callback approach, to ensure you call cb from removeEventHandlers when all the work is done, remember how many callbacks you're expecting and wait until you get that many before calling cb:
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings, function() {
addEventHandlers(newBindings);
});
}
function removeEventHandlers(oldBindings, cb) {
var waitingFor = oldBindings.length;
for (var i = 0; i < oldBindings.length; i++) {
Office.select("binding#"+oldBindings[i]).removeHandlerAsync(Office.EventType.BindingDataChanged, function (asyncResult) {
Office.context.document.bindings.releaseByIdAsync(oldBindings[i], function () {
if (--waitingFor == 0) {
cb();
}
});
});
}
}
But any time you have a callback system, you can Promise-ify it:
function removeHandlerPromise(obj, eventType) {
return new Promise(function(resolve, reject) {
obj.removeHandlerAsync(eventType, function(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
reject(asyncResult.error);
} else {
resolve(asyncResult.value);
}
});
});
}
function releaseByIdPromise(obj, value) {
return new Promise(function(resolve, reject) {
obj.releaseByIdAsync(value, function(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
reject(asyncResult.error);
} else {
resolve(asyncResult.value);
}
});
});
}
Then that lets you do this:
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings).then(function() {
addEventHandlers(newBindings);
});
}
function removeEventHandlers(oldBindings) {
return Promise.all(oldBindings.map(function(binding) {
return removeHandlerPromise(Office.select("binding#"+binding), Office.EventType.BindingDataChanged).then(function() {
return releaseByIdPromise(Office.context.document.bindings, binding);
});
});
}
Or you can give yourself a generic Promise-ifier for any async op that returns an AsyncResult:
function promisify(obj, method) {
var args = Array.prototype.slice.call(arguments, 2);
return new Promise(function(resolve, reject) {
args.push(function(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
reject(asyncResult.error);
} else {
resolve(asyncResult.value);
}
});
obj[method].apply(obj, args);
});
}
Then that lets you do this:
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings).then(function() {
addEventHandlers(newBindings);
});
}
function removeEventHandlers(oldBindings) {
return Promise.all(oldBindings.map(function(binding) {
return promisify(Office.select("binding#"+binding), "removeHandlerAsync", Office.EventType.BindingDataChanged).then(function() {
return promisify(Office.context.document.bindings, "releaseByIdAsync", binding);
});
});
}
How can I use nested context.executeQueryAsync with Deferred? Below is my code and I will explain what exactly I am looking for:
Code
function getValues() {
var dfd = $.Deferred(function () {
context.executeQueryAsync(function () {
var navigationItem = [];
// First Loop
while (termEnumerator.moveNext()) {
// Push Parent Terms in navigationItem array
navigationItem.push({ "name": ""});
// Get Sub Terms
context.executeQueryAsync(function () {
// Second Loop
while (termsEnum.moveNext()) {
// Push Sub Terms in navigationItem array
navigationItem.push({ "name": ""});
}
}, function (sender, args) {
console.log(args.get_message());
});
}
dfd.resolve(navigationItem);
}, function (sender, args) {
console.log(args.get_message());
dfd.reject(args.get_message());
});
});
return dfd.promise();
}
Basically I am trying to fetch Taxonomy (Terms & it's sub terms) in SharePoint Online using above code structure. Initially I have created an array named navigationItem and iterating through all the terms.
During iteration, first of all, I am pushing terms into this array and along with this, I am also getting it's sub terms if any and pushing it into the same array.
I want that code doesn't execute further until second loop completes it's execution. So that I will have final array while returning it to another function.
I want that code doesn't execute further until second loop completes
it's execution. So that I will have final array while returning it to
another function.
In this case, you need to have a defer for each executeQueryAsync.
Then, you need a create an overall defer to wait all of the async methods finished.
Here is the sample code for your reference:
(function ($) {
function executeQueryAsync(succeededCallback, failedCallback)
{
var period = Math.random() * 10000;
setTimeout(function () {
succeededCallback();
}, period);
}
function forEachAsync(items, funcAsync, callback)
{
var count = 0;
var total = $.Deferred();
function increment()
{
count++;
if(count == items.length)
{
total.resolve();
}
}
for (var i = 0; i < items.length; i++)
{
(function exec(item) {
var deferred = $.Deferred(function (defer) {
funcAsync(function () {
callback();
defer.resolve();
});
});
deferred.done(function () {
increment();
});
})(items[i]);
}
return total.promise();
}
var promise = forEachAsync([1, 2, 3, 4, 5], executeQueryAsync, function () {
console.log('call back executing + ' + Date.now());
});
promise.done(function () {
console.log("promise done");
});
})(jQuery);
so i have a function which checks if a checksum is changed and if so it calls the callback which is provided by a parameter.
var watchFileChange = function watchFileChange(oldChecksum, callback){
// some code about checking checksum
if(oldChecksum != newChecksum){
callback()
}
}
exports.watchFileChange = watchFileChange;
my Jasmin specs looks like this.
var t = require('../server.js');
describe("watchFileChange", function() {
spyOn(t.watchFileChange, 'Callback');
var file_false = {
'foo.txt': 'd41dcccc8f00b204e9800998ecf8427e'
}
var file_true = {
'foo.txt': 'd41d8cd98f00b204e9800998ecf8427e'
}
function Callback() {
console.log("Callback Called")
}
it("Checksum is not right, it should call Callback function", function() {
watchFileChange(file_false, Callback);
expect(Callback).toHaveBeenCalled();
});
});
But it just doesn't work that way because Callback is not defined i get that. So my question is there a way to check if the by parameter provided callback is called?
You can create a fake object where you can define you callback function, and then pass it as the argument
var init = {
callback: function() {
console.log("Callback Called")
}
};
describe("watchFileChange", function() {
beforeEach(function() {
spyOn(init, 'callback');
});
//...
it("Checksum is not right, it should call Callback function", function() {
watchFileChange(file_false, init.callback);
expect(init.callback).toHaveBeenCalled();
});
});
I want to write a library in javascript that can run the code like this:
seq.next(function(done){
setTimeout(done,3000);
}).next(function(done){
setTimeout(function(){
console.log("hello");
done();
},4000);
}).end(); //.next morever
Actually I want to write a library that can excecute asynchronous functions in order(sequentially). Each asynchronous function should run the "done" function on its end.
Could anyone please help me. Thanks very much!
The library is:
var seq = (function () {
var myarray = [];
var next = function (fn) {
myarray.push({
fn: fn
});
// Return the instance for chaining
return this;
};
var end = function () {
var allFns = myarray;
(function recursive(index) {
var currentItem = allFns[index];
// If end of queue, break
if (!currentItem)
return;
currentItem.fn.call(this, function () {
// Splice off this function from the main Queue
myarray.splice(myarray.indexOf(currentItem), 1);
// Call the next function
recursive(index);
});
}(0));
return this;
}
return {
next: next,
end: end
};
}());
And the use of this library is sth like this:
seq.next(function (done) {
setTimeout(done, 4000);
}).next(function (done) {
console.log("hello");
done();
}).next(function (done) {
setTimeout(function () {
console.log('World!');
done();
}, 3000);
}).next(function (done) {
setTimeout(function () {
console.log("OK");
done();
}, 2000);
}).end();
I have a function like this :
module.exports.download = function (cb) {
// Some Code
cb();
}
Is it the same to do this :
module.exports.copyimagefromalbumnext = function (callback) {
module.exports.download(callback);
}
or
module.exports.copyimagefromalbumnext = function (callback) {
module.exports.download( function () { callback(); } );
}
In advance thanks.
Is callback the same as function () { callback(); }
No. The second function neither cares about this context, passed arguments, nor the return value of an invocation. You could do
function() { return callback.apply(this, arguments); }
but that's just superfluous. Use the first approach and pass callback itself.