Write a library in javascript that can run asynchronous functions sequentially - javascript

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();

Related

JS init function not waiting for another function to completed

In my JS I want to wait for this fnDocumentTypeCount to be compelted before I go into the other with the logic for the init but it will not wait for that function to be completed.fnDocumentTypeCount is a $.ajax that I was going to return a number.
init: function () {
var countType = fnDocumentTypeCount(GroupId);
console.log(countType);
}
Use await:
init: async function () {
var countType = await fnDocumentTypeCount(GroupId);
console.log(countType);
}
Or here's the old way of doing this:
init: function () {
fnDocumentTypeCount(GroupId).then(countType => {
console.log(countType);
});
}

Nested context.executeQueryAsync with Deferred

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);

False positive unit test result

I have notice that unit testing in javascript and its frameworks is very painful. Many fail positive results. I.e
it('should call Event.create when all if ok', function () {
EventsPersistancyService.accept(message).then(function () {
sinon.assert.calledOnce(s3);
done();
});
});
EventsPersistancyService:
var EventsPersistancyService = {
accept: function acceptService(msg) {
var worker_id = WorkerCacheService.get('some login');
var app_category = AppCategoryService.get('some');
Event.create('msg'); <------------ **first**
var p = Q.all([worker_id, app_category]).then(function () {
var content = msg.content.toString();
content = JSON.parse(content);
var tmp = {};
return Event.create('msg'); <------ **second**
});
return p;
}
}
In that example test pass but it shouldn't. What am I doing wrong?
For starters, you never defined the done callback in your callback to it. But for promises, it is better to return the promise in your test, mocha will wait for promises to resolve.
it('should call Event.create when all if ok', function () {
return EventsPersistancyService.accept(message).then(function () {
sinon.assert.calledOnce(s3);
});
});
A working example with your done callback (note the done declaration as function argument):
it('should call Event.create when all if ok', function (done) {
EventsPersistancyService.accept(message).then(function () {
sinon.assert.calledOnce(s3);
done();
});
});

how to write a javascript function with optional parameter

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') })

Mocha & Sinon method spies

I am setting up tests for my application, and I wish to check a method was called x times using Sinon, my testing framework is Mocha.
How can I achieve this, below is the code I wish to test, I'm looking to ensure recursiveRequest is called x times by createClients.
Nodezilla.prototype.createClients = function(batched, i){
var self = this;
if(batched)
batchRequests();
if(batched == false && i < this.virtualUsers){
// set timeout to help prevent out of memory errors
setTimeout( function() {
self.createClients(false, i+1);
}, 0 );
}else{
this.recursiveRequest();
}
};
Nodezilla.prototype.recursiveRequest = function(){
var self = this;
self.hrtime = process.hrtime();
if(!this.halt){
self.reqMade++;
this.http.get(this.options, function(resp){
resp.on('data', function(){})
.on("end", function(){
self.onSuccess();
});
}).on("error", function(e){
self.onError();
});
}
};
Attempted test but no avail as callCount returns 0.
var assert = require('assert'),
sinon = require('sinon'),
nz = require('../Nodezilla'),
nt = new nz("localhost", 10);
describe('Nodezilla', function(){
describe('createClients', function(){
before(function() {
sinon.spy(nt, "recursiveRequest");
});
it('should call recursiveRequest() 10 times', function(){
nt.createClients(false, 0);
assert(nt.recursiveRequest.callCount);
});
});
});
createClients seems to be an async request, without a callback/promise.
This means your test is evaluated immediately, and does not wait for results.
I'd suggest to re-write the function with a callback or promise so you are able to act on the event of processing completed, and then this should work:
var assert = require('assert'),
sinon = require('sinon'),
nz = require('../Nodezilla'),
nt = new nz("localhost", 1);
describe('Nodezilla', function () {
describe('createClients', function () {
it('should call recursiveRequest() 10 times', function (itCallback) {
// Moved into the test:
sinon.spy(nt, "recursiveRequest");
nt.createClients(false, 0, function(){
// Needs to wait for action to actually be called:
assert(nt.recursiveRequest.callCount == 10);
// Now that the test is actually finished, end it:
itCallback();
});
});
});
});
Skipping the before statement, as this might interfere with scopes, sinon.spy being synchronous can be called inside the test.
Also note I have introduced a callback in this statement:
it('should call recursiveRequest() 10 times', function (callback) {
to hold the test from finishing before the inner callback is called.
Edit:
As for adding the callbacks, I'm not sure what does batchRequests() does, but go like that:
Nodezilla.prototype.createClients = function (batched, i, cb) {
var self = this;
if (batched)
batchRequests();
if (batched == false && i < this.virtualUsers) {
// set timeout to help prevent out of memory errors
setTimeout(function () {
self.createClients(false, i + 1, cb);
}, 0);
} else {
this.recursiveRequest(cb);
}
};
And then:
Nodezilla.prototype.recursiveRequest = function (cb) {
var self = this;
self.hrtime = process.hrtime();
if (!this.halt) {
self.reqMade++;
this.http.get(this.options, function (resp) {
resp.on('data', function () {
})
.on("end", function () {
self.onSuccess();
cb();
});
}).on("error", function (e) {
self.onError();
cb();
});
} else {
// I assume you are doing nothing in this case, so just call the callback:
cb();
}
};
Also note you can use the callback for error handling.

Categories

Resources