functionwork(arr) { let final = [] // arr.reduce(`callback`, `[initialValue]`) // - `callback` // - `promise` : the sequence of promise // - `item` : the item in the array // - `[initialValue]`: the initial state of promise sequence return arr.reduce((promise, item) => { return promise.then(result => { console.log(`A RESULT: ${result}`) return asyncRequest(item).then(result => { console.log(`B RESULT: ${result}`) final.push(result) return result }) }) }, Promise.resolve(0)) // when the last request arrives, show all the results together .then(() =>console.log(`FINAL R.: ${final}`)) }
Mock Async Request
// Using a promise to mock an async request // `e` type : int functionasyncRequest(e) { returnnewPromise((resolve, reject) => { setTimeout( () => resolve(e), // the time delay is `e` second(s). 1000 * e ); }); }
> work([1,2,3])
A RESULT: 0// the initial promise value Promise { <pending> } // 1s later B RESULT: 1 A RESULT: 1 // 2s later B RESULT: 2 A RESULT: 2 // 3s later B RESULT: 3 FINAL R.: 1,2,3
In Parallel
functionworkInParallel(arr){ returnPromise.all(arr.map(asyncRequest)) .then(final =>console.log(`FINAL R.: ${final}`)) }
All requests are sent in parallel. The function array.map takes an function asyncRequest and maps all elements to an array of promises. Then, Promise.all takes an array of promises, and create a promise that fulfills when all of them successfully complete.
> workInParallel([1,2,3])
Promise { <pending> } // 3s later FINAL R.: 1,2,3
> workInParallel([1,3,2]) Promise { <pending> } // 3s later FINAL R.: 1,3,2
Passing [1,2,3] and [1,3,2] to the parallel function, both of them cost 3 seconds to fulfill, and the order remains in the final result. Promise.all ensures results in the same order as the promises we passed in.
In Parallel 2
By extending Promise.all method as follows, each response can be displayed as soon as it arrives.
functionworkInParallel2(arr) { returnPromise.all(arr.map(result => { // init the requests console.log(`A RESULT: ${result}`) return asyncRequest(result).then(result => { // display the result as soon as it arrives console.log(`B RESULT: ${result}`) return result }) })) // when all responses arrive show final results .then(final =>console.log(`FINAL R.: ${final}`)) }
> workInParallel2([1,2,3])
A RESULT: 1 A RESULT: 2 A RESULT: 3 Promise { <pending> } // 1s later B RESULT: 1 // 1s later B RESULT: 2 // 1s later B RESULT: 3 FINAL R.: 1,2,3
In Parallel And Sequence
functionworkInParallelAndSequence(arr) { let final = [] return arr.map(asyncRequest) .reduce((sequence, item) => { // init a promise sequence console.log(`SEQ.:`, sequence) console.log(`---`) return sequence.then( (result) => { console.log(`A RESULT: ${result}`) console.log(`ITEM:`, item) console.log(`---`) // queue each promise request to the sequence return item }) .then( result => { console.log(`B RESULT: ${result}`) // get the response final.push(result) return result }) }, Promise.resolve(0)) .then(() =>console.log(`FINAL R.: ${final}`)) }
> workInParallelAndSequence([1,2,3])
SEQ.: Promise { 0 } // Adding 1 req, 0 req resolved --- SEQ.: Promise { <pending> } // Adding 2 req, 1 req pending --- SEQ.: Promise { <pending> } // Adding 3 req, 2 req pending --- A RESULT: 0 ITEM: Promise { <pending> } // fulfilling 1 req --- // 1s later B RESULT: 1 A RESULT: 1 ITEM: Promise { <pending> } // fulfilling 2 req --- // 1s later B RESULT: 2 A RESULT: 2 ITEM: Promise { <pending> } // fulfilling 3 req --- // 1s later B RESULT: 3 FINAL R.: 1,2,3
Let’s assume in a single page, there are 3 units loading contents by promise requests.
Header contains relatively less information and returns very quickly.
Main contains articles. It costs the longest time among all units.
Sidebar contains advertisement. We do not want to impress the audience with advertisements, while the article is still loading. The sidebar usually returns more quickly than Main.
In short, our intention is to make sure that Sidebar displays after Main.
Such method can be applied in many scenarios, when the main content (feed flow, article, etc.) is slower than less important contents (comments, advertisements, etc.).
Todo
I find that debugging asynchronous functions is quite hard even enhanced with Promise. Instead of console.log, I believe there will be a better tool to detail requesting/responding stacks.