How to await callback function to finished? - javascript

I have two simple functions:A function which returns a promise
function showBootbox(){
return new Promise(function (resolve, reject) {
bootbox.confirm('Are you sure ? ',resolve);
});
}
and a function which uses a callback.
function getBootboxValue(callback) {
showBootbox().then(function (result) {
callback(result);
});
}
Now the problem is that i can't await for callback to finished.
if(condition){
getBootboxValue(function(result){
if(result){
//code
}
});
}
console.log('a');
console.log(a) is executing before I got the result of promise. How can I do this without using async/await mechanism ?
Thanks in advance!

If I didn't get it wrong, your idea is to console.log('a') immidiately if the condition is not met and console.log('a') at the end of the callback if the condition is met.
If that is so, one option could be to return the promise of getBootboxValue(callback) when the condition is met and an already fulfilled promise if the condition is not met. You'd then use a callback for that promise that would contain the console.log('a').
function showBootbox() {
return new Promise(function(resolve, reject) {
console.log('Are you sure ? ');
resolve();
});
}
function getBootboxValue(callback) {
return showBootbox().then(function(result) {
callback(result);
});
}
function test(condition) {
var cbk = function(result) {
console.log('Launching callback');
if (result) {
//code
}
},
aux = condition ? getBootboxValue(cbk) : Promise.resolve(null);
aux.then(function() {
console.log('a')
});
}
test(true);
test(false);
Hope it helps.

I think this is what you are after. If you need to conditionally execute an async function and then run some code else run that code anyway you can put the code in a function and call it in either situation:
if(condition){
getBootboxValue(function(result){
if(result){
//code
}
doSomething();
});
} else {
doSomething();
}
function doSomething() {
console.log('a');
}

Related

Add timeout function inside function before return value

This code is working fine , but I need to add something in timeout function before return in firstFunction()
function LastFunction(){
var answer = firstFunction();
console.log(answer)
}
function firstFunction() {
//Do something;
return somevalue
}
How to add timeout function inside function before return value ?
function firstFunction() {
setTimeout (function(){
var something = "something here"
},1000)
return something
}
You'll need to use Promises. Your code inside the setTimeout will be delayed but everything outside of it will continue to run synchronously.
function LastFunction(){
firstFunction().then(function(val) {
console.log(val)
return val
})
}
function firstFunction() {
var promise = new Promise(function(resolve, reject) {
setTimeout(function(){
var something = "something here"
resolve(something)
},1000)
})
return promise
}

Asynchronous callbacks in a loop

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

Loop on a promise indefinitely until rejection

I have a function that does some async work and returns a Promise, and I want to execute this function indefinitely until the promise is rejected.
Something like the following :
doSomethingAsync().
.then(doSomethingAsync)
.then(doSomethingAsync)
.then(doSomethingAsync)
// ... until rejection
I made a little CodePen so I can test potential solutions : http://codepen.io/JesmoDrazik/pen/pbAovZ?editors=0011
I found several potential answers but nothing seems to work for my case.
If anyone has a solution, I'd be glad, because I just can't find anything !
Thanks.
You can do
(function loop(){
doSomethingAsync().then(loop);
})();
But looking at your pen it's not clear where the rejection should come from. If you want to stop repeating an operation when the user clicks a button, you can change a state in the button handling and then do
(function loop(){
doSomethingAsync().then(function(){
if (!stopped) loop();
});
})();
Made a modification to your codepen
var FAKE_COUNT = 0;
function doSomething() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('doing something async: ' + FAKE_COUNT)
if (FAKE_COUNT < 10) {
resolve();
} else {
reject();
}
FAKE_COUNT ++;
}, 1000);
});
}
const button = document.querySelector('.js-button');
button.addEventListener('click', () => {
// maybe we can do something here ?
})
function test() {
doSomething().then(test).catch(() => {
console.log("Rejected")
});
}
test();
FAKE_COUNT just becomes the flag, so if you want to stop the promise with a click instead of a count you could just make it a bool and check that when executing the async task
Depending on where you want the logic and rejection to take place, but assuming you want the promise itself to be self executing (otherwise the asynchronous execution itself could loop) it could return itself as a new promise:
function doSomething() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('doing something async');
resolve();
}, 1000);
}).then(()=>doSomething());
}
For the rejection part, the easiest way would be to introduce a flag, (although that would make the promise a little less self containing):
var stop = false;
function doSomething() {
return new Promise((resolve, reject) => {
if(stop)
reject();
else{
setTimeout(() => {
console.log('doing something async');
resolve(); //(check for stop could be done here as well)
}, 1000);
}
}).then(()=>doSomething());
}
const button = document.querySelector('.js-button');
button.addEventListener('click', () => {
stop = true;
});
doSomething();

Javascript promise not delaying function execution

I'm using ES6 javascript promises in Chrome and am having trouble understanding why the promise executed within the function _getStatus() is not returning the result argument in the success handler which would result in the alert box containing "done". Instead, I get an alert box that says "undefined".
myNameSpace = function(){
var obj = {
groupA: {
status: "inactive"
},
groupB: {
status: "active"
}
};
function _getStatus(group){
_finishTask().then(function(result){
return result; // doesn't return anything
});
}
function _finishTask(){
var promise = new Promise(function(resolve, reject){
// do some task before resolving
resolve("done");
});
return promise;
};
return{
getStatus:_getStatus
}
}();
$(function(){
alert(myNameSpace.getStatus("groupA")); // why is this "undefined" instead of "done"?
});
Because this is not how Promises work. You need to make sure both _getStatus and _finishTask return Promise objects. Then you will be able to use those promises API methods to execute subsequent code what promise is resolved.
So your code should look something like this:
myNameSpace = function() {
var obj = {
groupA: {
status: "inactive"
},
groupB: {
status: "active"
}
};
function _getStatus(group) {
return _finishTask().then(function(result) {
return result + " and tested";
});
}
function _finishTask() {
return new Promise(function(resolve, reject) {
// do some task before resolving
resolve("done");
});
};
return {
getStatus: _getStatus
}
}();
myNameSpace.getStatus("groupA").then(alert);
Finally, regarding this construction:
return _finishTask().then(function(result) {
return result;
});
_finishTask returns a Promise object, when this promise is resolved you get into then callback. Whatever value you return from this callback becomes a new resolution value for the subsequent success callbacks down the resolution chain.
Demo: http://plnkr.co/edit/K1SWKuTYA3e46RxdzkCe?p=preview
You cant return a result from an asynchronous function as the code running it has already finished by the time the response is returned.
You can however pass in a callback to execute once the code is complete:
function _getStatus(group, callback){
_finishTask().then(function(result){
callback(result);
});
}
$(function(){
myNameSpace.getStatus("groupA", function(result) {
alert(result);
});
});
or use the promise api itself (in this case your _getStatus method is a little redundant):
function _getStatus(group){
return _finishTask();
}
$(function(){
myNameSpace.getStatus("groupA").then(function(result) {
alert(result);
});
});

Strange behaviour in javascript Promise

Considering code snippet below,
function one(){
var prm = new Promise(function(resolve,reject){
});
prm.customKey = function(){
}
return prm;
}
function two(){
return one().then(function(){
//something
});
}
Now calling the function two, returns a promise in which 'customKey' is missing
function three(){
return one();
}
But while doing the same thing in function three(without handling success using 'then'),
returns a promise which has 'customKey' in it.
Can someone clarify me whats really happening and why?
As you can see from "Mozilla Docs" then method returns new Promise (e.g: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then).
If you want to assign a function to retrieve / do something in resolve function do it like this:
var prm = new Promise((resolve, reject) => {
let customKeyFunction = () => {
console.log("I'm custom key function.");
};
resolve(customKeyFunction);
})
From now on you can call this function like that:
function two() {
return one().then(customKey => {
customKey();
})
}

Categories

Resources