jquery deferred and promise in a loop - javascript

Here is something wrong. All functions should be called synchronously. Could anyone give me a hint? I think that is an error in the for loop
Here is my code:
var radioValues = msg.options;
var cn = gotoReport()
.then(clickReport)
.then(clickReportFake)
.then(clickNext);
for (var i = 0; i < radioValues.length; i++){
cn = cn.then(clickOption(radioValues[i])).then(clickNext);
}
cn.then(clickSendToFacebook).then(clickFinish);
//all called functions look like that
function clickNext(){
return process(function(){
console.log("clickNext");
var next = $('button:contains("Weiter")');
$(next).click();
},3000);
}
function process(action, ms) {
var deferred = $.Deferred();
timer = setInterval(function() {
deferred.notify();
}, 1000);
setTimeout(function() {
clearInterval(timer);
action();
deferred.resolve();
}, ms);
// return deferred;
return deferred.promise();
}
function sleep(ms)
{
return(new Promise(function(resolve, reject) {
setTimeout(function() { resolve(); }, ms);
}));
}
Here is the output
gotoReport
clickOption=option3
clickReport
clickReportFake
clickNext
clickNext
clickSendToFacebook
clickFinish

One major issue is here:
cn.then(clickOption(radioValues[i]))
You are not passing the clickOption function as argument to then -- you are invoking it. Instead do:
cn.then(clickOption.bind(null, radioValues[i]))

Related

return promise from a function called in settimeout

The following code gives me an error stating getConfigDetails...then is not a function. I want to return a promise from the function getConfigDetails if the isConfigLoaded variable is set to true otherwise keep calling it untill it is.
var getConfigDetails = function () {
if ($rootScope.isconfigloaded) {
configDetails.roles = $rootScope.orgConfig.roles.slice();
configDetails.departments = $rootScope.orgConfig.departments.slice();
configDetails.levels = $rootScope.orgConfig.levels.slice();
configDetails.designation = $rootScope.orgConfig.designation.slice();
return Promise.resolve();
} else {
setTimeout(function(){
getConfigDetails();
},200);
}
};
getConfigDetails().then(function(){});
You could do the following:
var getConfigDetails = new Promise(function(resolve, reject){
var ticker = setInterval(function(){
if ($rootScope.isconfigloaded) {
//the other stuff
clearInterval(ticker);
resolve();
}
}, 200);
});
You should be able to use it like getConfigDetails.then(function(){})
Notice its not a function though, just a promise. If you really want it to be a function do the following:
function getConfigDetails() {
return new Promise(function(resolve, reject){
var ticker = setInterval(function(){
if ($rootScope.isconfigloaded) {
//the other stuff
clearInterval(ticker);
resolve();
}
}, 200);
});

Call a repeating function with different parameters after the previous instance finished

I want to call a second instance of the same function but with different values, after the first instance has completely finished, currently it calls both instances at the same time.
function printLetterByLetter(destination, message, speed) {
var i = 0;
var interval = setInterval(function () {
document.getElementById(destination).innerHTML += message.charAt(i);
i++;
if (i > message.length) {
clearInterval(interval);
}
}, speed);
}
printLetterByLetter("hc-a", "Hello world", 100);
printLetterByLetter("hc-b", "Hello world again.", 100);
How can I do this?
You can do using promise which wait for your first function execution then execute next otherwise you can use async/await which is also a good alternative.
Using Promise
function printLetterByLetter(destination, message, speed) {
var i = 0;
return new Promise(function(resolve, reject) {
var interval = setInterval(function() {
document.getElementById(destination).innerHTML += message.charAt(i);
i++;
if (i > message.length) {
clearInterval(interval);
resolve(true);
}
}, speed);
});
}
printLetterByLetter("hc-a", "Hello world", 100).then(function(resolve) {
printLetterByLetter("hc-b", "Hello world again.", 100);
}, function(reject) {});
Using async/await
function printLetterByLetter(destination, message, speed) {
var i = 0;
return new Promise(function(resolve, reject) {
var interval = setInterval(function() {
document.getElementById(destination).innerHTML += message.charAt(i);
i++;
if (i > message.length) {
clearInterval(interval);
resolve(true);
}
}, speed);
});
}
(async function() {
await printLetterByLetter("hc-a", "Hello world", 100);
printLetterByLetter("hc-b", "Hello world again.", 100);
})()
You can use Promises or async/await in order to do this. See the example below, that achieves your goal by utilizing Promises:
function printLetterByLetter(destination, message, speed) {
var i = 0;
// Return promise instance which you can use to execute code after promise resolves
return new Promise(function(resolve) {
var interval = setInterval(function() {
document.getElementById(destination).innerHTML += message.charAt(i);
i++;
if (i > message.length) {
clearInterval(interval);
// Resolve promise and execute the code in "then" block
resolve();
}
}, speed);
});
}
printLetterByLetter('hc-a', 'Hello world', 100).then(function() {
// This code gets executed when promise resolves
printLetterByLetter('hc-b', 'Hello world again.', 100);
});
<div id="hc-a"></div>
<div id="hc-b"></div>
You could use a classical approach with a stack and test the stack if the actual interval has ended.
var printLetterByLetter = function () {
function startInterval() {
var data = stack.shift(),
i = 0;
return data && setInterval(function () {
document.getElementById(data.destination).innerHTML += data.message[i++];
if (i >= data.message.length) {
clearInterval(interval);
interval = startInterval();
}
}, data.speed);
}
var stack = [],
interval;
return function (destination, message, speed) {
stack.push({ destination, message, speed });
interval = interval || startInterval();
};
}();
printLetterByLetter("hc-a", "Hello world", 100);
printLetterByLetter("hc-b", "Hello world again.", 50);
printLetterByLetter("hc-c", "See you later, alligator!", 200);
<div id="hc-a"></div>
<div id="hc-b"></div>
<div id="hc-c"></div>

How to run a function after two async functions complete

Say I have an array of functions that invoke a setTimeout.
[
function(cb){
setTimeout(function(){
cb('one');
}, 200);
},
function(cb){
setTimeout(function(){
cb('two');
}, 100);
}
]
Is there a way to access the time parameter (200, 100) and save the sum of that to a variable?
I want to execute a function only when both of those functions are done
A better approach is to use promises and Promise.all:
var task1 = new Promise(function(resolve,reject) {
setTimeout(function() {
//do something
resolve();
}, 100);
});
var task2 = new Promise(function(resolve,reject) {
setTimeout(function() {
//do something
resolve();
}, 200);
});
Promise.all([task1, task2]).then(function() {
//will be executed when both complete
});
You can mimic it with a closure for the count.
function out(s) {
var node = document.createElement('div');
node.innerHTML = s + '<br>';
document.getElementById('out').appendChild(node);
}
var f = [
function (cb) { setTimeout(function () { cb('one'); }, 100); },
function (cb) { setTimeout(function () { cb('two'); }, 200); }
],
useCounter = function () {
var count = 2;
return function (s) {
count--;
out(s + ' ' + count);
!count && out('done');
}
}();
f[0](useCounter);
f[1](useCounter);
<div id="out"></div>

javascript promise schedule multiple function

How to use promise schedule multiple function , should I have to make it like 2 way nest the callback?
on serverside I use nodejs and co make generateor,
then make it looks like below
co(function *() {
yield q1();
yield q2();
yield q3();
...
Is there some similar way syntax with promise ?
var q1 = function() {
return new Promise(function (fulfill, reject){
setTimeout(function(){
fulfill(console.log('q1'));
}, 100);
});
};
var q2 = function() {
return new Promise(function (fulfill, reject){
setTimeout(function(){
fulfill(console.log('q2'));
}, 100);
});
};
var q3 = function() {
console.log("done!");
};
1
q1().then(function() {
q2();
}).then(function() {
q3();
});
2
q1().then(function() {
q2().then(function() {
q3();
});
});
with the code you've got, you can simply do this
q1().then(q2).then(q3);
return the promise from the then callback like
var q1 = function() {
return new Promise(function(fulfill, reject) {
setTimeout(function() {
snippet.log('q1')
fulfill();
}, 1000);
});
};
var q2 = function() {
return new Promise(function(fulfill, reject) {
setTimeout(function() {
snippet.log('q2')
fulfill();
}, 1000);
});
};
var q3 = function() {
snippet.log("done!");
};
q1().then(function() {
return q2();
}).then(function() {
q3();
});
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Excecute JavaScript function after previous one completes

I want to execute several JavaScript functions in a specific order (like below) and not until the previous function has completed. I have tried this so many ways. Any suggestions? Any help is so greatly appreciated, I have been stuck on this for so long. Thanks in advance!
function savedSearch(e){
applySearch1("ColumnA");
applySearch2("ColumnB");
applySearch3("ColumnC");
applySearch4("ColumnD");
applySearch5("ColumnE");
applySearch6("ColumnF");
}
To add in response to the other answer by Mohkhan, you can also use the async library.
https://github.com/caolan/async
That will keep you out of callback hell and make for a much easier to read list of functions.
You should use callbacks in all your applySearch* functions.
Like this.
function savedSearch(e){
applySearch1("ColumnA", function(){
applySearch2("ColumnB", function(){
applySearch3("ColumnC", function(){
applySearch4("ColumnD", function(){
applySearch5("ColumnE",function(){
applySearch6("ColumnF", function(){
// You are done
});
});
});
});
});
});
}
If use jquery, it has deferred objects which helps you deal with async functions.
Here is an example:
// Code goes here
$(document).ready(function() {
function Pipe() {
this.asyncTasks = [];
this.observers = {};
this.on = function(eventName, fn) {
if (!this.observers[eventName]) {
this.observers[eventName] = $.Callbacks;
}
this.observers[eventName].add(fn);
}
this.fire = function(eventName, data) {
if (this.observers[eventName]) {
this.observers[eventName].fire(data);
}
}
this.register = function(asyncFn, context) {
this.asyncTasks.push(new Task(asyncFn, context));
}
this.start = function() {
this.fire('start');
this._next();
}
this._next = function() {
var task = this.asyncTasks.shift();
if (task) {
task.execute().then($.proxy(this._next, this));
} else {
this.fire('end');
}
}
var Task = function(fn, context) {
this.fn = fn;
this.context = context;
this.execute = function() {
if (!this.fn) {
throw new Exception("Failed to execute.");
}
var promise = this.fn.call(context);
this.fn = null;
return promise;
}
}
}
var bookMoview = function() {
var dfd = jQuery.Deferred();
// Resolve after a random interval
setTimeout(function() {
dfd.resolve("The movie is booked");
console.log("The movie is booked");
}, Math.floor(400 + Math.random() * 2000));
// Return the Promise so caller can't change the Deferred
return dfd.promise();
}
var bookTaxi = function() {
var dfd = jQuery.Deferred();
// Resolve after a random interval
setTimeout(function() {
console.log("Taxi is booked");
dfd.resolve("Taxi is booked");
}, Math.floor(400 + Math.random() * 2000));
// Return the Promise so caller can't change the Deferred
return dfd.promise();
}
var pipe = new Pipe();
pipe.register(bookMoview);
pipe.register(bookTaxi);
pipe.start();
});

Categories