One-By-One Promise

Let’s define a function to simulate calling API via Promise and setTimeout():

1
2
3
4
5
6
7
var callAPI = (api, arg) => new Promise((resolve, reject)=>{ // <- callAPI() always return this promise
setTimeout(()=> {
let msg = `API "${api}" called successfully! ==> ${JSON.stringify(arg)}`
console.log(msg)
resolve(msg) // You can get msg via then(): callAPI(...).then((msg)=>{ ... })
}, Math.floor(Math.random()*1000)) // Simulate unstable network & server latency
})

Use like this:

1
2
3
callAPI("AddUser", { username: "ib", password: "ib" }).then((x)=>{
console.log("API test!")
})

Result

1
2
API "AddUser" called successfully! ==> {"username":"ib","password":"ib"}
API test!

Call Multiple APIs Simultaneously

When you have to call a lot of asynchronous APIs simultaneously, you may use Promise.all() like this::

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var newUsers = [
{ username: "ib", password: "ib" },
{ username: "garry", password: "garry" },
{ username: "marry", password: "marry" }
]

var deferredPromises = []

for (let user of newUsers) {
deferredPromises.push(callAPI("AddUser", user))
}
Promise.all(deferredPromises).then((msgList)=>{
// all promises have been resolved in here...
console.log("All promises have been resolved here! Message List:", msgList)
// ...
})

Result

1
2
3
4
API "AddUser" called successfully! ==> {"username":"marry","password":"marry"}
API "AddUser" called successfully! ==> {"username":"garry","password":"garry"}
API "AddUser" called successfully! ==> {"username":"ib","password":"ib"}
All promises have been resolved here! Message List: Array [ "API "AddUser" called successfully! …", "API "AddUser" called successfully! …", "API "AddUser" called successfully! …" ]

Call Multiple APIs One-By-One

Now consider: how to call APIs one-by-one? That is to say, after previous API has replied, then call another?

The answer is: pass another Promise into resolve():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var newUsers = [
{ username: "ib", password: "ib" },
{ username: "garry", password: "garry" },
{ username: "marry", password: "marry" }
]
var runner = () => new Promise((resolve, reject) => { // <- runner() always return this promise
if (newUsers.length==0) {
console.log("All APIs called and responded one-by-one!")
return resolve("One By One Done!") // Pass a non-promise into resolve(), and this chain will stop at this resolve()
}
let first = newUsers[0]
callAPI("AddUser", first).then((msg)=>{
newUsers.shift() // Remove first from Array newUsers
resolve(runner()) // Pass another promise into resolve(), the passed promise will also be resolve()
}).catch((err)=>{
reject(err)
})
})

runner()

Result

1
2
3
4
API "AddUser" called successfully! ==> {"username":"ib","password":"ib"}
API "AddUser" called successfully! ==> {"username":"garry","password":"garry"}
API "AddUser" called successfully! ==> {"username":"marry","password":"marry"}
All APIs called and responded one-by-one!

When you pass a Promise object into resolve(), that passed Promise will going to be resolved.
See Promise.resolve() and Promise to get more details.