0

In order to use some online service, I need to call an API three times.

  1. Upload the file
  2. Request an operation
  3. Download the file

I can handle all operations individually but I have hard times to sequence them as they are asynchronous. I wish I can handle all operations in one function call and all I am asking here is some advice to start on the right foot.

I have been playing with promises but got lost in the progress.

function main(){
    //Pseudo code
    calling async step1
    exit if step1 failed
    calling async step2
    exit if step2 failed
    calling async ste3
    exit if step3 failed
    return OK
}

Thanks in advance.

Loic
  • 2,173
  • 10
  • 13
  • We need to see your real code in order to advise you specifically. No pseudo code please. Real code. We also need to know how the interfaces work, whether there is a version of the APIs that return promises or only a version with plain callbacks? – jfriend00 Dec 05 '19 at 16:56
  • I understand that. Point is I wasn't even sure that the code I wrote made sense. My intention was to get advice on the main architecture then to try doing some progress on a good track. I wasn't like I knew what I was doing and faced some execution issue. Once that said, I tried to find forums for such "early design" discussions with no luck. But feel free to recommend one. – Loic Dec 05 '19 at 17:17
  • Even if you don't know how to code it to start, it will help you get a lot more complete answers if you show the exact APIs you're trying to call and how you're trying to sequence them. That lets people tell you about things you don't even know to ask in offering a more complete answer and perhaps even show you code that would work as a basis to get started with. Pseudo-code is nearly always the wrong choice here. You got away with it this time because I decided to take the time to write a generic tutorial on using `async/await` as an answer. Most of the time people will not. – jfriend00 Dec 05 '19 at 17:20
  • Well that's understood and I am grateful for that. – Loic Dec 05 '19 at 17:37

1 Answers1

2

Since you've given us no real code and no specific information on your APIs, I will offer an answer assuming that the APIs return promises or can be made to return promises. In that case, sequencing and doing error handling is quite simple:

ascync function main() {
     let step1Result = await step1();
     let step2Result = await step2();
     let step3Result = await step3();
     return finalValue;
}

// usage
main().then(finalResult => {
    console.log(finalResult);
}).catch(err => {
    console.log(err);
});

Some things to know:

  1. Because main is declared async, it can use await internal to its implementation.
  2. Because main is delcared async, it will always return a promise
  3. This code assumes that step1(), step2() and step3() return promises that are linked to the completion or error of one or more asynchronous operations.
  4. When the function is executing, as soon as it hits the first await, the function will return an unresolved promise back to the caller.
  5. If any of the await stepX() calls reject (e.g. have an error), that will abort further execution of the function and reject the promise that was previously returned with that specific error. It works analogous to throw err in synchronous programming, but the throw is caught automatically by the async function and turned into a reject for the promise that it already returned.
  6. Your final return value in the function is not actually what is returned because remember, a promise was already returned from the function when it hit the first await. Instead, the value you return becomes the resolved value of that promise that was already returned.
  7. If your API interfaces don't currently return promises, then you can usually find a wrapper that someone has done to create a version that will return promises (since promises are the modern way of working with asynchronous interfaces in Javascript). Or, you can create your own wrapper. In node.js, you can use util.promisify() or you can manually make your own wrapper (just takes a few lines of code).
  8. If you need to catch an error within the function in order to handle it and continue, you can either wrap a given await call in try/catch or use .catch() on the promise and "handle" the error and continue processing, again similar to handling exceptions in synchronous code.

If any of the steps had an error and rejected their promise, then main() will abort and reject similar to throwing an exception in synchronous code.

See also:

How to chain and share prior results with Promises

jfriend00
  • 683,504
  • 96
  • 985
  • 979