I have an app with two submit buttons. The first initiates an API call via a promise which takes a number of seconds. The second button gathers some user input then processes the output of the API request with their selection.
I'd like to start the request, have the user make their selection, then wait for the initial request to complete when they hit submit:
this.upload.addEventListener('change', (event) => {
....
// initial submit button
API.getHumanFaceLandmarks(data.corrected).then((landmarks) => {
console.log(landmarks);
this.humanFeatures = extractHumanFeatures.beginRender(
landmarks,
data.canvas,
this.EYE_MASK,
this.MOUTH_MASK,
this.EYE_SELECTOR,
this.MOUTH_SELECTOR);
}).catch(error => console.log('error', error));
});
pet.addEventListener('click', (event) => {
// second submit
renderPetswitch.outputFinalImage(
event.target.dataset.name,
this.humanFeatures, // <--- how do i wait for this value to be resolved before executing this function?
this.OUTPUT_CANVAS);
})
My API method looks like this:
getHumanFaceLandmarks: async function(data) {
console.log(data.substring(0, 50) '...');
const headers = new Headers();
headers.append("Content-Type", "application/json");
const body = JSON.stringify({
"image": data
});
const requestOptions = {
method: 'POST',
headers: headers,
body: body,
redirect: 'follow'
};
const response = await fetch(constants.HUMAN_FACE_LANDMARKS_ENDPOINT, requestOptions);
return response.json();
}
How do I wait for an exisiting promise to complete when the user submits the second step of the process?
I'm trying to streamline the experience and thus would prefer not to do the request in one go.
CodePudding user response:
You want to await two future events:
- The resolution of
getHumanFaceLandmarks()
- The second submit
In such a situation Promise.all
can help out, but for that to work, you need to first promisify the second event (the second submit).
To do that, you could promisify listining to a single event occurrence:
// Helper function: promisify event listening
const nextEvent = (elem, event) => new Promise(resolve =>
elem.addEventListener(event, resolve, { once: true })
);
Now you can do this:
(async function() {
const uploadEvent = await nextEvent(this.upload, 'change');
// ....
// initial submit button
const [landmarks, petEvent] = await Promise.all([
API.getHumanFaceLandmarks(data.corrected),
nextEvent(pet, 'click')
]);
// At this point we both have the landmarks and the second submit.
console.log(landmarks);
this.humanFeatures = extractHumanFeatures.beginRender(
landmarks,
data.canvas,
this.EYE_MASK,
this.MOUTH_MASK,
this.EYE_SELECTOR,
this.MOUTH_SELECTOR
);
renderPetswitch.outputFinalImage(
petEvent.target.dataset.name,
this.humanFeatures,
this.OUTPUT_CANVAS
);
})(); // immediately invoked.
You would need to have logic that prevents the user to do things in the wrong order. For instance:
- The second submit should not be allowed when the upload had not been done yet.
- Once the upload has been done, the user should not be allowed to do that again. The next action should be the second submit. Or if you would allow that, you need to include logic to cancel the previous upload processing...
CodePudding user response:
pet.addEventListener('click', (event) => {
await.API.getHumanFaceLandmarks.then( //Rest of the function
renderPetswitch.outputFinalImage(
event.target.dataset.name,
this.humanFeatures, // <--- how do i wait for this value to be resolved before executing this function?
this.OUTPUT_CANVAS);
})
if you make this function async, you should be able to do something like await.