Promise not getting resolved after setTimeOut - javascript

I'm using cordova's speech recognition plugin where after user click's on speech button startRecognition is triggered but if after 10000ms if user does not speaks anything then the stopListening() function should be triggered and this goes on continuously unless the user says exit.
I'm using setTimeout wrapped inside a promise and when that promise is resolved then i'm resolving the promise which is triggering the cordova plugin for speech recognition
This code will continously run speech recognition unless user says exit.
listenMsgAndReplyRepeat() {
const self = this;
this.listenMsg().then(res => {
alert('got result ' + res);
if (res === 'Exit') {
self.exitFromApp();
} else if (res === 'Success') {
self.listenMsgAndReplyRepeat();
} else if (res === 'Stopped') {
alert('the speech recognition was stopped');
self.botReply('Hello? Do you Want me to Exit?');
self.listenMsgAndReplyRepeat();
} else {
self.botReply('Some error occured will detecting speech');
}
});
}
This code is the one which starts speech recognition
listenMsg() {
const self = this;
// Verify if recognition is available
return new Promise(function(resolve, reject) {
self
.isRecognitionAvailable()
.then(function(available) {
if (available) {
return window.plugins.speechRecognition.hasPermission();
}
})
.then(function(hasPermission) {
function startRecognition() {
self.speakPopUp = true;
return self
.startRecognition({
language: 'en-US',
showPopup: false,
matches: 2
// showPartial: true
})
.then(function(result) {
clearTimeout(self.stopListen);
self.speakPopUp = false;
if (result[0] === 'exit') {
resolve('Exit'); //working
}
self.botReply(result[0]).then(res => {
resolve('Success'); //working
});
})
.catch(function(err) {
reject('Error');
});
}
if (!hasPermission) {
self
.requestPermission()
.then(function() {
self.stopSpeech().then(res => {
self.speakPopUp = false;
resolve('Stopped'); //this resolve is not working
});
startRecognition();
})
.catch(function(err) {
console.error('Cannot get permission', err);
reject('Error');
});
} else {
self.stopSpeech().then(res => {
self.speakPopUp = false;
resolve('Stopped'); //this resolve is not working
});
startRecognition();
}
})
.catch(function(err) {
console.error(err);
reject('Error');
});
});
}
The resolve inside local function startRecognition is working but the one inside the if else condition is not working
Here is the stopRecognition code
stopSpeech() {
const self = this;
return new Promise(function(resolve, reject) {
self.stopListen = setTimeout(() => {
self.stopListening().then(res => {
clearTimeout(self.stopListen);
resolve('stopped');
});
}, 10000);
});
}
The resolve inside setTimeOut is working.
I'm assigning setTimeOut to a variable because if the user speaks i have to clear it so that stopListening is not triggered.

I was able to solve this issue by using Promise.all().I wrapped the timeout inside a promise and passed it into the promise array and after that i pushed the stopListening promise to it.
const promises = [];
promises.push(self.delay(10000));
promises.push(self.stopListening());
Promise.all(promises).then((res) => {
self.speakPopUp = false;
resolve('Stopped');
});
delay(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t);
});

Related

Code throwing unhandled rejection error when running promise

I am trying to write a Javascript promise that resolves and rejects the desired variables. I am getting the error message below after running in the console
[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch().
code: 'ERR_UNHANDLED_REJECTION'
Here is my code
Js File:
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
let grimePromise = new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject("User Left");
} else if (userWatchingGrimeVids) {
reject("This user is a G");
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
grimePromise.then((message) => {
console.log("Success: " + message);
});
grimePromise.catch((message) => {
console.log("You Failed: " + message);
});
By calling the .then() and the .catch() handler on two different places, you actually end up with two different promises - each of .then() and .catch() returns a new one. The promise returned by .then() will not be caught by the separate .catch() handler:
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
let grimePromise = new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject("User Left");
} else if (userWatchingGrimeVids) {
reject("This user is a G");
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
grimePromise
.then((message) => {
console.log("Success: " + message);
})
.catch(() => console.log(1));
grimePromise.catch((message) => {
console.log(2);
console.log("You Failed: " + message);
});
Therefore, one promise gets turned into two. Each of them will adopt the state of the original promise. When the original is rejected, both the derived promises reject. Yet only one is handled.
Instead, you can directly specify the .catch() in the same promise chain as the .then():
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
let grimePromise = new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject("User Left");
} else if (userWatchingGrimeVids) {
reject("This user is a G");
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
grimePromise
.then((message) => {
console.log("Success: " + message);
})
.catch((message) => {
console.log("You Failed: " + message);
});
<h1>Check the browser console - no unhandled promise rejections</h1>
Or alternatively, specify both handlers in the then():
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
let grimePromise = new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject("User Left");
} else if (userWatchingGrimeVids) {
reject("This user is a G");
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
grimePromise
.then(
(message) => {
console.log("Success: " + message);
},
(message) => {
console.log("You Failed: " + message);
}
);
<h1>Check the browser console - no unhandled promise rejections</h1>
The reason this isn't working is because you didn't have a .catch() on the first one. It was throwing a rejection, but you weren't handling it gracefully with a catch, so it threw.
Here is your code working - I just moved your catch block to go after the .then:
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
const grimePromise = new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject('User Left');
} else if (userWatchingGrimeVids) {
reject('This user is a G');
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
grimePromise
.then((message) => {
console.log('Success: ' + message);
})
.catch((message) => {
console.log('You Failed: ' + message);
});
Just as a tip though, you should only reject whenever the function is unsuccessful in some way. That could be a timeout, a network error, incorrect input etc. Whatever is inside of a reject should ideally be an error.
Additionally, I'd recommend using async await, as it's much easier to read and more manageable. You can easily do this by creating a function which returns your new Promise, then awaiting it like so:
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
const grime = () => {
return new Promise((resolve, reject) => {
if (grimeUserLeft) {
reject(new Error('User Left'));
} else if (userWatchingGrimeVids) {
resolve('This user is a G');
} else {
resolve("Congrats. Your channel doesn't suck");
}
});
};
const doStuff = async () => {
try {
const result = await grime();
console.log(result);
} catch (error) {
console.error(error);
}
};
doStuff();
To make this truly asynchronous, you should ideally be doing some async stuff inside of the promise. This can be demonstrated with a setTimeout:
const grimeUserLeft = false;
const userWatchingGrimeVids = true;
const grime = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (grimeUserLeft) {
reject(new Error('User Left'));
} else if (userWatchingGrimeVids) {
resolve('This user is a G');
} else {
resolve("Congrats. Your channel doesn't suck");
}
}, 2000);
});
};
const doStuff = async () => {
try {
const result = await grime();
console.log('result finished after 2 seconds');
console.log(result);
} catch (error) {
console.error(error);
}
};
doStuff();

Promise resolved before entire chain of promises is resolved

I have a chain of promises as a function in my app. Each of my service functions returns a deferred.promise;
Considering the following scenario I have where main getUser service calls getUserPreferences and getUserFavourites asynchronously, the console.log after resolving getUserData is being resolved before getUserFavourites even responds! Shouldn't the promise in getUserData be resolved once getUserFavourites responds?
In fact 'got all user data' from the console.log is in the console before getUserFavourites is called. Literally straight after getUser responds almost like getUserData().then( only resolves the top level promise and make the underlying 2 asynchronous...
What am I doing wrong here?
var user = 'blabla';
function getUserData() {
var deferred = $q.defer();
getUser(user).then(
function(response) {
getUserPreferences(response.user).then(
function(preferences) {
console.log('preferences', preferences);
},
function() {
deferred.reject();
}
);
getUserFavourites(response.user).then(
function(favourites) {
deferred.resolve();
console.log('favourites', favourites);
},
function() {
deferred.reject();
}
);
},
function() {
deferred.reject();
}
);
return deferred.promise;
}
getUserData().then(
function() {
console.log('got all user data');
}
);
A way to fix that is to use the async/await to make the code look synchronous.
var user = 'blabla';
async function getUserData() {
try {
var deferred = $q.defer();
let userInfo = await getUser(user)
let userPrefs = await getUserPreferences(userInfo.user)
console.log('preferences', userPrefs);
let userFavourites = await getUserFavourites(userInfo.user)
deferred.resolve();
console.log('favourites', userFavourites);
return deferred.promise;
} catch (error) {
deferred.reject();
}
}
getUserData().then(
function() {
console.log('got all user data');
}
);
Use $q.all to return a composite promise:
function getUserData() {
return getUser(user).then(function(response) {
var preferencesPromise = getUserPreferences(response.user);
var favouritesPromise = getUserFavourites(response.user);
return $q.all([preferencesPromise, favouritesPromise]);
});
}
Then extract the data from the composite promise:
getUserData().then([preferences, favourites] => {
console.log('got all user data');
console.log(preferences, favourites);
}).catch(function(error) {
console.log(error);
});
The $q.all method returns a single promise that will be resolved with an array/hash of values, each value corresponding to the promise at the same index/key in the promises array/hash. If any of the promises is resolved with a rejection, this resulting promise will be rejected with the same rejection value.
For more information, see
AngularJS $q Service API Reference - $q.all
You must RETURN the nested promise in order to have a chain.
The problem here is you have 2 nested promises so you will need to return a Promise.all (or $q.all in your case) taking an array of the 2 promises returned by getUserPreferences and getUserFavorites:
var user = 'blabla';
function getUserPreferences(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({color: 'green'});
},500);
});
}
function getUserFavorites(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve([{id: 1, title: 'first favorite'}, {id: 2, title: 'second favorite'}]);
},500);
});
}
function getUser(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve(user);
},500);
});
}
function getUserData() {
return getUser().then(
function(user) {
console.log(user);
var prefPromise = getUserPreferences(user).then(
function(preferences) {
console.log('preferences', preferences);
return preferences;
},
function(error) {
console.log("Error getting preferences");
throw error;
}
);
var favPromise = getUserFavorites(user).then(
function(favourites) {
console.log('favourites', favourites);
return favourites;
},
function(error) {
console.log("Error getting favorites");
throw error;
}
);
return Promise.all([
prefPromise,
favPromise
]);
},
function(err) {
console.log("Error getting user");
throw err;
}
);
}
getUserData().then(
function(results) {
console.log(results);
}
);
Note that for demo purpose I am using es6 Promise instead of angular $q but the spirit is the same:
$q.defer() => new Promise()
$q.all => Promise.all
As the Promise pattern is great to simplify async code and make it look like synchronous code, you can simplify the upper example with something like:
var user = { name: 'blabla'};
function getUserPreferences(user){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({color: 'green'});
},500);
});
}
function getUserFavorites(user){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve([{id: 1, title: 'first favorite'}, {id: 2, title: 'second favorite'}]);
},500);
});
}
function getUser(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve(user);
},500);
});
}
function getUserData() {
return getUser()
.then(user => { // user is resolved
// running parallel promises to get user infos:
return Promise.all([
user,
getUserPreferences(user),
getUserFavorites(user)
]);
})
.then(results => {
// wrapping the results into something more semantic:
let userData = results[0];
userData.prefs = results[1];
userData.favs = results[2];
return userData;
});
}
getUserData().then(
function(userData) {
console.log('Final result:');
console.log(userData);
}
);

Node.js using multiple promises

I currently try to use two kind of promises. One for the overall convensation, and one to get the userids to usernames.
The code works when its ran first time, and is looking something like this:
The output above is what i wanted.
But when i run the query again, i get this:
what is wrong with my code? what do i need to do to make the promises go correctly?
code:
function getconvensations(userid) {
return new Promise(function(resolve, reject) {
convensations.find({members: userid}).lean().then(function (convensations) {
var promises = convensations.map(function (currentConvensation) {
return new Promise(function (resolve, reject) {
var realnames = [];
var usernames = currentConvensation.members.map(function (CurrentUser) {
Core.userDetails(CurrentUser).then(function (user) {
realnames.push(user.username);
console.log("RESOLVING USERNAMES");
resolve();
});
});
Promise.all(usernames).then(function () {
console.log("GET LATEST MESSAGE");
latestMessage(currentConvensation._id).then(function (message) {
console.log("Messages: ");
console.log(message);
currentConvensation.spesificmessage = message;
currentConvensation.users = realnames;
currentConvensation.otherend = (currentConvensation.members[0] == userid ? realnames[0] : realnames[1]);
console.log("RESOLVE LATEST MESSAGE");
resolve();
});
});
});
});
Promise.all(promises).then(function () {
console.log("FINISHED CONVENSATIONS");
console.log("-------------------------");
console.log(convensations);
console.log("-------------------------");
return resolve(convensations);
}).catch(console.error);
});
});
}
caller:
} else if(action == 'getconvensations') {
Messages_model.getconvensations(req.user._id).then(function (response) {
res.json(response);
});
}
You have a race condition here:
new Promise(function (resolve, reject) {
…
currentConvensation.members.map(function (CurrentUser) {
Core.userDetails(CurrentUser).then(function (user) {
resolve();
});
});
…
latestMessage(currentConvensation._id).then(function (message) {
resolve();
});
…
});
There are arbitrarily many tasks executing concurrently, and the first promise that fulfills will call resolve().
The solution is to avoid the Promise constructor antipattern and never ever call new Promise or resolve manually! Instead, chain promise callbacks to each other using the then method, and return new promises from every function to allow the caller to wait for them.
function getconvensations(userid) {
return convensations.find({members: userid}).lean().then(function (convensations) {
// ^^^^^^
var promises = convensations.map(function (currentConvensation) {
var usernamepromises = currentConvensation.members.map(function (CurrentUser) {
console.log("GETTING USERNAME");
return Core.userDetails(CurrentUser).then(function (user) {
// ^^^^^^
console.log("FULFILLED USERNAME");
return user.username;
// ^^^^^^
});
});
return Promise.all(usernamepromises).then(function (realnames) {
// ^^^^^^
console.log("FULFILLED ALL USERNAMES");
currentConvensation.users = realnames;
currentConvensation.otherend = (currentConvensation.members[0] == userid ? realnames[0] : realnames[1]);
console.log("GETTING LATEST MESSAGE");
return latestMessage(currentConvensation._id);
// ^^^^^^
}).then(function (message) {
console.log("FULFILLED LATEST MESSAGE");
console.log("Message: ", message);
currentConvensation.spesificmessage = message;
});
});
return Promise.all(promises).then(function () {
// ^^^^^^
console.log("FINISHED ALL CONVENSATIONS");
console.log("-------------------------");
console.log(convensations);
console.log("-------------------------");
return convensations;
// ^^^^^^
});
});
}

sequelize maximum transactions at one time

So considering I have a seeder like so:
var seedDatabase = function () {
var promises = [];
promises.push(createProductTypes());
promises.push(createCompensationTypes());
promises.push(createDataSources());
promises.push(createPeriodsAndStages());
promises.push(createExportDestinations());
return Promise.all(promises);
};
function createCompensationTypes() {
return models.sequelize
.transaction(
{
isolationLevel: models.sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED
},
function (q) {
return models.CompensationType
.findAll()
.then(function (result) {
if (!result || result.length == 0) {
return models.CompensationType
.bulkCreate(compensationTypes, { transaction: q })
.then(function () {
console.log("CompensationTypes created");
})
}
else {
console.log("CompensationTypes seeder skipped, already objects in the database...");
return;
}
});
})
.then(function (result) {
console.log("CompensationTypes seeder finished...");
return;
})
.catch(function (error) {
console.log("CompensationTypes seeder exited with error: " + error.message);
return;
});
};
For some reason this hangs on execution. Yet, when I comment any one of the promises added to the array everything goes smoothly as it should.
Also when I do the following in my seedDatabase function, it works too:
var seedDatabase = function () {
var promises = [];
promises.push(createProductTypes());
promises.push(createDataSources());
promises.push(createPeriodsAndStages());
promises.push(createExportDestinations());
return Promise.all(promises).then(function() {
return createCompensationTypes()
});
};
which is bizarre since obviously my code is working but still hangs on an extra promise. Hence my question, is there a maximum of concurrent promises or transactions when using sequelizeJS? Or am I overlooking something else here?

Bluebird.js Promise not chaining .then()s

socket.on('new video', function(data) {
console.log("New video")
var addToCueP = Promise.promisify(addToCue)
var getCueFromDbP = Promise.promisify(getCueFromDb)
addToCueP(data.id, socket.nickname)
.then(function() {
return getCueFromDbP();
})
.then(function() {
console.log("Emit change video")
io.sockets.emit('change video', {id: data.id, title: data.title, nick: socket.nickname});
})
});
I am using Bluebird for promises but I'm having issues, the addToCue function gets called but the other functions after for example the getCuefromDb and the Socket emitter isnt getting triggered, does anyone have any idea where I'm going wrong?
addToCue()
var addToCue = function(id, user) {
console.log("Add to cue")
var video = new Video();
video.id = id;
video.user = user;
video.save(function(err, data) {
if (err) {
console.log(err)
} else {
return true
}
});
}
getCueFromDb()
var getCueFromDb = function(callback) {
Video.find({}).exec(function(err, videos) {
if (err) {
return err;
}
if (videos.length) {
cue = []; // empty array
videos.forEach(function(video) {
cue.push(video.id) // push all the videos from db into cue array
});
io.sockets.emit('send cue', {cue: cue});
console.log("getCueFromDb", cue)
if (callback) {
callback();
return
}
else {
return
}
}
else {
cue = [];
io.sockets.emit('send cue', {cue: cue});
console.log("getCueFromDb (no videos)", cue)
if (callback)
callback()
else
return
}
})
}
addToCue() does not accept the right types of arguments in order to call .promisify() on it- therefore promisify does not work properly with it.
The last argument to addToCue() MUST be a callback that is called when the async operation is done and the first argument to that callback must be an error value and the second argument can be a result.
Now, since you control the code to addToCue(), you should just change its code to return a promise that is resolved/rejected based on the underlying async operation and not use .promisify() at all.
var addToCue = function(id, user) {
return new Promise(function(resolve, reject) {
console.log("Add to cue")
var video = new Video();
video.id = id;
video.user = user;
video.save(function(err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
Alternatively, you could use .promisify() on video.save() or .promisifyAll() on the Video object.
Or, if your Video interface already supports promises, you can just use it's native support and return that promise.

Categories

Resources