I wrote some code that uses promises. It seems that in the Promise environment, I can queue an action, and the action callback is never called. In the callback environment, when I queue an action, the action callback is always called.
I made a test case. If you run it and click Do Operations Using Callbacks, it will run. If you use 1 as the input number, the results will get filled in as 2, 12, and 36.
If you click Do Operations Using Promises, the first result, 2, will be filled in, and then it will stop. If you open the developer tools and go to the console tab, you can see what's going on. I put a bunch of console logs in the program. You can see the action get enqueued. But then the action callback isn't called.
These operations are just times2, add10, and times3. These are just dummy operations. In real life, op3 might be sendDataToSomeoneWhoNeedsIt. Op2 might be collectTogetherTheData. And op2 may not be able to get all of the data itself, so it might call op1, getThePortionOfTheDataThatRequiresUserInput.
Okay, hold your breath! I'm going to type in all the files. (Is there some jsfiddle for Salesforce?)
Apex class cubsSvrThreeOperationsController
public with sharing class cubsSvrThreeOperationsController {
@AuraEnabled
// public static Integer times2(Integer num) {return 2 * num;}
// Nope. Can't handle Integer yet.
public static String times2(String numstr) {
Integer num = Integer.valueOf(numstr);
num *= 2;
String numstr2 = String.valueOf(num);
return numstr2;
}
@AuraEnabled
public static String add10(String numstr) {
Integer num = Integer.valueOf(numstr);
num += 10;
String numstr2 = String.valueof(num);
return numstr2;
}
@AuraEnabled
public static String times3a(String numstr) {
Integer num = Integer.valueOf(numstr);
num *= 3;
String numstr2 = String.valueof(num);
return numstr2;
}
// I had to name this times3a because times3 got stuck in
// the Salesforce internals, and couldn't be recognized.
// Thief! Baggins! We hates it, we hates it, we hates it
// forever!
}
cubsThreeOperationsApp.app
<aura:application >
<c:cubsThreeOperations />
</aura:application>
cubsThreeOperations.cmp
<aura:component controller="cubsSvrThreeOperationsController" implements="flexipage:availableForAllPageTypes">
<aura:attribute name="input" type="integer" default="1"/>
<aura:attribute name="output1" type="integer" default="0"/>
<aura:attribute name="output2" type="integer" default="0"/>
<aura:attribute name="output3" type="integer" default="0"/>
<div>
<label>Input number: </label>
<ui:inputNumber value="{!v.input}"/>
<ui:button label="Do Operations Using Callbacks" press="{!c.doOperationsUsingCallbacks}"/>
<ui:button label="Do Operations Using Promises" press="{!c.doOperationsUsingPromises}"/>
<ui:button label="Do Operations Using getCallback" press="{!c.doOperationsUsingGetCallback}"/>
</div>
<div>
<label>Result of operation 1: </label>
<ui:outputNumber value="{!v.output1}"/>
</div>
<div>
<label>Result of operation 2: </label>
<ui:outputNumber value="{!v.output2}"/>
</div>
<div>
<label>Result of operation 3: </label>
<ui:outputNumber value="{!v.output3}"/>
</div>
<br/>
</aura:component>
cubsThreeOperationsController.js
({
doOperationsUsingCallbacks: function (cmp, event, helper) {
cmp.set('v.output1', 0);
cmp.set('v.output2', 0);
cmp.set('v.output3', 0);
helper.doOperationsUsingCallbacks(cmp, event, helper);
},
doOperationsUsingPromises: function (cmp, event, helper) {
cmp.set('v.output1', 0);
cmp.set('v.output2', 0);
cmp.set('v.output3', 0);
helper.doOperationsUsingPromises(cmp, event, helper);
},
doOperationsUsingGetCallback: function (cmp, event, helper) {
cmp.set('v.output1', 0);
cmp.set('v.output2', 0);
cmp.set('v.output3', 0);
helper.doOperationsUsingGetCallback(cmp, event, helper);
}
})
cubsThreeOperationsHelper.js
({
doOperationsUsingCallbacks: function (cmp, event, helper) {
var num = cmp.get('v.input');
helper.doOperationCallback3(cmp, event, helper, num);
},
// Operation 3 defines its result in terms of values it doesn't have yet.
doOperationCallback3: function (cmp, event, helper, num) {
helper.doOperationCallback2(cmp, event, helper, num, function (cmp, event, helper, num) {
var action = cmp.get('c.times3a');
var numstr = num.toString();
action.setParams({
numstr: numstr
});
action.setCallback(this, function (response) {
var state = response.getState();
if (state === 'SUCCESS') {
var outNumStr = response.getReturnValue();
var outNum = parseInt(outNumStr);
cmp.set('v.output3', outNum);
} else {
console.log('Failed');
}
});
$A.enqueueAction(action);
});
},
doOperationCallback2: function (cmp, event, helper, num, callback) {
helper.doOperationCallback1(cmp, event, helper, num, function (cmp, event, helper, num) {
var action = cmp.get('c.add10');
var numstr = num.toString();
action.setParams({
numstr: numstr
});
action.setCallback(this, function (response) {
var state = response.getState();
if (state === 'SUCCESS') {
var outNumStr = response.getReturnValue();
var outNum = parseInt(outNumStr);
cmp.set('v.output2', outNum);
callback(cmp, event, helper, outNum);
} else {
console.log('Failed');
}
});
$A.enqueueAction(action);
});
},
doOperationCallback1: function (cmp, event, helper, num, callback) {
var action = cmp.get('c.times2');
var numstr = num.toString();
action.setParams({
numstr: numstr
});
action.setCallback(this, function (response) {
var state = response.getState();
if (state === 'SUCCESS') {
var outNumStr = response.getReturnValue();
var outNum = parseInt(outNumStr);
cmp.set('v.output1', outNum);
callback(cmp, event, helper, outNum);
} else {
console.log('Failed');
}
});
$A.enqueueAction(action);
},
doOperationsUsingPromises: function (cmp, event, helper) {
var num = cmp.get('v.input');
helper.doOperationPromise3(cmp, event, helper, num);
},
doOperationPromise3: function (cmp, event, helper, num) {
console.log('doOperationPromise3 - entered');
helper.doOperationPromise2(cmp, event, helper, num)
.then(function (num) {
console.log('doOperationPromise3 - entered then function');
var action = cmp.get('c.times3a');
var numstr = num.toString();
action.setParams({
numstr: numstr
});
action.setCallback(this, function (response) {
console.log('doOperationPromise3 - entered action callback');
var state = response.getState();
if (state === 'SUCCESS') {
var outNumStr = response.getReturnValue();
var outNum = parseInt(outNumStr);
cmp.set('v.output3', outNum);
} else {
console.log('Failed');
}
});
console.log('doOperationPromise3 - about to enqueue action');
$A.enqueueAction(action);
}, function () {});
},
doOperationPromise2: function (cmp, event, helper, num) {
console.log('doOperationPromise2 - entered');
return new Promise(function (resolve, reject) {
console.log('doOperationPromise2 - entered promise function');
helper.doOperationPromise1(cmp, event, helper, num)
.then(function (num) {
console.log('doOperationPromise2 - entered then function');
var action = cmp.get('c.add10');
var numstr = num.toString();
action.setParams({
numstr: numstr
});
action.setCallback(this, function (response) {
console.log('doOperationPromise2 - entered action callback');
var state = response.getState();
if (state === 'SUCCESS') {
var outNumStr = response.getReturnValue();
var outNum = parseInt(outNumStr);
cmp.set('v.output2', outNum);
console.log('doOperationPromise2 - about to resolve promise');
resolve(outNum);
} else {
console.log('Failed');
reject();
}
});
console.log('doOperationPromise2 - about to enqueue action');
$A.enqueueAction(action);
}, function () {});
});
},
doOperationPromise1: function (cmp, event, helper, num) {
console.log('doOperationPromise1 - entered');
return new Promise(function (resolve, reject) {
console.log('doOperationPromise1 - entered promise function');
var action = cmp.get('c.times2');
var numstr = num.toString();
action.setParams({
numstr: numstr
});
action.setCallback(this, function (response) {
console.log('doOperationPromise1 - entered action callback');
var state = response.getState();
if (state === 'SUCCESS') {
var outNumStr = response.getReturnValue();
var outNum = parseInt(outNumStr);
cmp.set('v.output1', outNum);
console.log('doOperationPromise1 - about to resolve promise');
resolve(outNum);
} else {
console.log('Failed');
reject();
}
});
console.log('doOperationPromise1 - about to enqueue action');
$A.enqueueAction(action);
});
},
doOperationsUsingGetCallback: function (cmp, event, helper) {
var num = cmp.get('v.input');
helper.doOperationGetCallback3(cmp, event, helper, num);
},
doOperationGetCallback3: function (cmp, event, helper, num) {
console.log('doOperationGetCallback3 - entered');
helper.doOperationGetCallback2(cmp, event, helper, num)
.then($A.getCallback(function (num) {
console.log('doOperationGetCallback3 - entered then function');
var action = cmp.get('c.times3a');
var numstr = num.toString();
action.setParams({
numstr: numstr
});
action.setCallback(this, function (response) {
console.log('doOperationGetCallback3 - entered action callback');
var state = response.getState();
if (state === 'SUCCESS') {
var outNumStr = response.getReturnValue();
var outNum = parseInt(outNumStr);
cmp.set('v.output3', outNum);
} else {
console.log('Failed');
}
});
console.log('doOperationGetCallback3 - about to enqueue action');
$A.enqueueAction(action);
}), $A.getCallback(function () {}) );
},
doOperationGetCallback2: function (cmp, event, helper, num) {
console.log('doOperationGetCallback2 - entered');
return new Promise(function (resolve, reject) {
console.log('doOperationGetCallback2 - entered promise function');
helper.doOperationPromise1(cmp, event, helper, num)
.then($A.getCallback(function (num) {
console.log('doOperationGetCallback2 - entered then function');
var action = cmp.get('c.add10');
var numstr = num.toString();
action.setParams({
numstr: numstr
});
action.setCallback(this, function (response) {
console.log('doOperationGetCallback2 - entered action callback');
var state = response.getState();
if (state === 'SUCCESS') {
var outNumStr = response.getReturnValue();
var outNum = parseInt(outNumStr);
cmp.set('v.output2', outNum);
console.log('doOperationGetCallback2 - about to resolve promise');
resolve(outNum);
} else {
console.log('Failed');
reject();
}
});
console.log('doOperationGetCallback2 - about to enqueue action');
$A.enqueueAction(action);
}), $A.getCallback(function () {}) );
});
},
doOperationGetCallback1: function (cmp, event, helper, num) {
console.log('doOperationGetCallback1 - entered');
return new Promise(function (resolve, reject) {
console.log('doOperationGetCallback1 - entered promise function');
var action = cmp.get('c.times2');
var numstr = num.toString();
action.setParams({
numstr: numstr
});
action.setCallback(this, function (response) {
console.log('doOperationGetCallback1 - entered action callback');
var state = response.getState();
if (state === 'SUCCESS') {
var outNumStr = response.getReturnValue();
var outNum = parseInt(outNumStr);
cmp.set('v.output1', outNum);
console.log('doOperationGetCallback1 - about to resolve promise');
resolve(outNum);
} else {
console.log('Failed');
reject();
}
});
console.log('doOperationGetCallback1 - about to enqueue action');
$A.enqueueAction(action);
});
}
})
})
Perhaps promises are just new to Salesforce, and the situation will improve in the coming days. Reference this article: ES6 Promises do not exist in controllers, helpers under Lightning Locker