preface
Jin SAN Yin Si, as a senior student who is about to become a graduate, I can’t wait to put my resume into byte’s flying book department. I thought about weighing a few pounds, but I didn’t think it was revealed 🤣, and my dream of going to big factory fell down on promsie.all. But young people should always have the will to fight, from where to climb up! The following is the recheck time.
What is a Promise. All?
Promise.all is a method on an ES6 Promise object that wraps multiple Promise instances into a single Promise instance. Here’s how MDN describes Promise.all:
- The promise.all () method accepts an iterable of promises. Array, Map, and Set are all ES6 iterable types), and only one Promise instance is returned. The result of the resolve callbacks to all of those entered promises is an Array. The Promise’s resolve callback is executed when all the incoming Promise’s resolve callbacks have ended, or when no promises are left in the input iterable. Its Reject callback execution throws an error as soon as any incoming promise’s Reject callback is executed or an invalid promise is entered, and reject is the first error message thrown.
I put on my 300-degree myopic glasses and carefully extracted the key words in this description:
Promise.all
The return value of is a newPromise
Instance.Promise.all
Accept a traversable data container in which each element should bePromise
Instance. I’m just saying, let’s say this container is an array.- Each of the arrays
Promise
Instances are successful (bypendding
State transition tofulfilled
The state),Promise.all
To success. thesePromise
Instance-ownedresolve
The results are set in the original order in an array asPromise.all
的resolve
Results. - You only need one in the array
Promise
The instance failed (bypendding
State transition torejected
The state),Promise.all
Will fail.Promise.all
的.catch()
I’m going to catch thisreject
.
Native promise.all tests
Let’s take a look at the original Promise. All.
const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('P2 delay one second')},1000)})const p3 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('P3 delay of two seconds')},2000)})const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('P5 Rejected delay 1.5sec')},1500)})// All Promise instances succeed
Promise.all([p1, p2, p3])
.then(res= > {
console.log(res)
})
.catch(err= > console.log(err)) // Prints after 2 seconds ['p1', 'P2 delay 1 second ',' P3 delay 2 seconds']
// A Promise instance failed
Promise.all([p1, p2, p4])
.then(res= > {
console.log(res)
})
.catch(err= > console.log(err)) // p4 rejected
// A delayed failed Promise
Promise.all([p1, p2, p5])
.then(res= > {
console.log(res)
})
.catch(err= > console.log(err)) // after 1.5 seconds, print p5 Rejected
// Two Promise instances failed
Promise.all([p1, p4, p5])
.then(res= > {
console.log(res)
})
.catch(err= > console.log(err)) // p4 rejected
Copy the code
Pay attention to
P4 and p5 above need to be commented out if promise.all is not passed in, because an instance of a Promise that calls reject will report an error if.catch() is not used to catch an error. But if the Promise instance defines its own.catch, the.catch() method of promise.all is not triggered.
OK, theory exists, practice begins!
Implement promise.all manually
Promise.all
Accepts an array and returns a new onePromise
The instance
Promise.MyAll = function (promises) {
return new Promise((resolve, reject) = >{})}Copy the code
- All in the array
Promise
The instances are successful,Promise.all
To success. Not surprisingly, we need an array to collect thisPromise
The instanceresolve
The results. But there’s an old saying that goes, “Don’t worry about ten thousand, just in case,” in case there’s an element in the array that isn’tPromise
What to do — then you have to use itPromise.resolve()
Get it done. There’s another question here,Promise
Instances cannot be called directlyresolve
The way. We have to be.then()
To collect the results. Be careful to keep the order of the results.
Promise.MyAll = function (promises) {
let arr = []
return new Promise((resolve, reject) = > {
promises.forEach((item, i) = > {
Promise.resolve(item).then(res= > {
arr[i] = res
})
})
})
}
Copy the code
- Will collect the results (array
arr
) as a parameter to the outer layerresolve
Methods. Here we certainly have a judgment condition, how to judge allPromise
And the examples are all successful? This code is easy for beginners to write (yes, I am 😭) :
if (arr.length === promises.length) resolve(arr)
Copy the code
Zan thinks about what Promise is used for — handling asynchronous tasks. Yeah, a lot of asynchronous tasks take time, and what if the last of those promises gets made first? The arR array has only the last item, and all the items in front are empty. So here we should create a counter that increments each time a Promise instance succeeds:
Promise.MyAll = function (promises) {
let arr = [],
count = 0
return new Promise((resolve, reject) = > {
promises.forEach((item, i) = > {
Promise.resolve(item).then(res= > {
arr[i] = res
count += 1
if (count === promises.length) resolve(arr)
})
})
})
}
Copy the code
- And then finally dealing with failure, there are two ways to write it, the first way is to use
.catch()
Method capture failed:
Promise.MyAll = function (promises) {
let arr = [],
count = 0
return new Promise((resolve, reject) = > {
promises.forEach((item, i) = > {
Promise.resolve(item).then(res= > {
arr[i] = res
count += 1
if (count === promises.length) resolve(arr)
}).catch(reject)
})
})
}
Copy the code
The second way to write this is to pass a second argument to the.then() method, which is a callback to handle errors:
Promise.MyAll = function (promises) {
let arr = [],
count = 0
return new Promise((resolve, reject) = > {
promises.forEach((item, i) = > {
Promise.resolve(item).then(res= > {
arr[i] = res
count += 1
if (count === promises.length) resolve(arr)
}, reject)
})
})
}
Copy the code
The test case
Here’s the Promise. All done, put it to the test (rub your hands) :
const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('P2 delay one second')},1000)})const p3 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('P3 delay of two seconds')},2000)})const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('P5 Rejected delay 1.5sec')},1500)})// All Promsie were successful
Promise.MyAll([p1, p2, p3])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // Prints after 2 seconds ['p1', 'P2 delay 1 second ',' P3 delay 2 seconds']
// A Promise fails
Promise.MyAll([p1, p2, p4])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p4 rejected
// A delayed failed Promise
Promise.MyAll([p1, p2, p5])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // Print p5 rejected delay 1.5 seconds
// Two failed promises
Promise.MyAll([p1, p4, p5])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p4 rejected
Copy the code
“OhOhOhOh~~~~”, and the native promise.all run not exactly like, but exactly the same. Strike while the iron is hot, as the old saying goes. I went to a learning site (MDN Web Docs (mozilla.org)) and saw the methods Promise objects use to handle multiple promises at once: Promise.race, promise.any, promise.allsettle. Since the teacher taught us to draw inferences by analogy, carefully look at the description of the three methods, I really give out 😄.
Promise.race
Promise.race literally means a race, in which the state changes the fastest. The fastest Promise succeeds.
Let’s take a look at the native Promise.race effect
Native promise.race test
const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('P2 delay one second')},1000)})const p3 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('P3 delay of two seconds')},2000)})const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('P5 Rejected delay 1 SEC')},1500)})// P1 has no delay, p2 has 1s delay, p3 has 2s delay
Promise.race([p1, p2, p3])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p1
// p4 reject without delay
Promise.race([p4, p2, p3])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p4 rejected
P5 delay 1.5s reject, P2 delay 1s
Promise.race([p5, p2, p3])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // Prints after 1s: P2 delay is 1 second
Copy the code
Theory exists, practice begins
Written Promise. Race
The overall process is similar to Promise, except that the logic of processing the Promise instances in the array is different. Here, we need to take the Promise result that changes the state fastest as the result of promise.race, which is relatively simple, and the code is as follows:
Promise.MyRace = function (promises) {
return new Promise((resolve, reject) = > {
// There is no need to use an index, just to loop through each item
for (const item of promises) {
Promise.resolve(item).then(resolve, reject)
}
})
}
Copy the code
The test case
Or just a few cases, I will not repeat to write 😁
// P1 has no delay, p2 has 1s delay, p3 has 2s delay
Promise.MyRace([p1, p2, p3])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p1
// p4 reject without delay
Promise.MyRace([p4, p2, p3])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p4 rejected
P5 delay 1.5s reject, P2 delay 1s
Promise.MyRace([p5, p2, p3])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // Prints after 1s: P2 delay is 1 second
Copy the code
As you can see, the results are consistent with the native promise.race, success!
Promise.any
Promise. Any/all can be seen as opposite. Promise.any will succeed as long as one of the Promise instances succeeds, and promise. any will fail only if all Promise instances fail, at which point promise. any will aggregate all failures/errors together. Returns a failed promise and an instance of type AggregateError. MDN says that this method is still in the experimental stage, if the Node or browser version is too late, it may not work, you can test it yourself.
Native promise.any test
const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('P2 delay one second')},1000)})const p3 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('P3 delay of two seconds')},2000)})const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('P5 Rejected delay 1.5sec')},1500)})// All promises were successful
Promise.any([p1, p2, p3])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p1
// Both promises succeed
Promise.any([p1, p2, p4])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p1
// There is only one delayed success Promise
Promise.any([p2, p4, p5])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p2 delay is 1 second
// All promises fail
Promise.any([p4, p5])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // AggregateError: All promises were rejected
Copy the code
If there are multiple successful Promise instances in promise.race, the result that succeeds most quickly is used as the result of resolve.
OK, theory exists, practice begins
Written Promise. Any
- Let’s write it out first
Promise.any
Overall structure of:
Promise.MyAny = function (promises) {
return new Promise((resolve, reject) = > {
promises.forEach((item, i) = >{})})}Copy the code
- Here with
Promise.all
The logic is the opposite, we need to collectreject
的Promise
, also need an array and a counter, use the counter to determine if allPromise
All instances fail. Also failed in collectionPromise
We need to put a failure mark on the results so we can analyze them.
Promise.MyAny = function (promises) {
let arr = [],
count = 0
return new Promise((resolve, reject) = > {
promises.forEach((item, i) = > {
Promise.resolve(item).then(resolve, err= > {
arr[i] = { status: 'rejected'.val: err }
count += 1
if (count === promises.length) reject(new Error('No promise will succeed'))})})})}Copy the code
Instead of using the AggregateError instance specified on MDN, write by hand as you like and write 😄 as you feel comfortable
The test case
// All promises were successful
Promise.MyAny([p1, p2, p3])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p1
// Both promises succeed
Promise.MyAny([p1, p2, p4])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p1
// There is only one delayed success Promise
Promise.MyAny([p2, p4, p5])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // p2 delay is 1 second
// All promises fail
Promise.MyAny([p4, p5])
.then(res= > console.log(res))
.catch(err= > console.log(err)) // No promise succeeds
Copy the code
Promise.allSettled
Sometimes, our coders have a special need: What if we want a set of Promise instances to wait until they finish asynchronously, whether they succeed or not, and then proceed to the next step? Promise. AllSettled.
nativePromise.allSettled
test
const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('P2 delay one second')},1000)})const p3 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('P3 delay of two seconds')},2000)})const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('P5 Rejected delay 1.5sec')},1500)})// All Promise instances succeed
Promise.allSettled([p1, p2, p3])
.then(res= > console.log(res))
.catch(err= > console.log(err))
/ / /
// { status: 'fulfilled', value: 'p1' },
// {status: 'depressing ', value:' P2 delay one second '},
// {status: 'depressing ', value:' P3 delay two seconds'}
// ]
// One Promise failed
Promise.allSettled([p1, p2, p4])
.then(res= > console.log(res))
.catch(err= > console.log(err))
/ / /
// { status: 'fulfilled', value: 'p1' },
// {status: 'depressing ', value:' P2 delay one second '},
// { status: 'rejected' , value: 'p4 rejected' }
// ]
// All promises fail
Promise.allSettled([p4, p5])
.then(res= > console.log(res))
.catch(err= > console.log(err))
/ / /
// { status: 'rejected', reason: 'p4 rejected' },
// {status: 'rejected', reason: 'p5 Rejected delay 1.5sec '}
// ]
Copy the code
As you can see, like Promise.any, Promise.AllSettled tags all the collected results. The Promise. AllSettled will not become a pity state, no matter how the group of Promise instances are settled, they will become a pity state.
OK, theory exists, practice begins
Written Promise. AllSettled
Resolve all the results of each Promise instance (whether they were successful or not) by using an array. The logic of collecting successful Promise results was implemented in promise. all, and the logic of collecting failed Promise results was dealt with in promise. any. This wave, this wave is doing the same — all the same.
Promise.MyAllSettled = function (promises) {
let arr = [],
count = 0
return new Promise((resolve, reject) = > {
promises.forEach((item, i) = > {
Promise.resolve(item).then(res= > {
arr[i] = { status: 'fulfilled'.val: res }
count += 1
if (count === promises.length) resolve(arr)
}, (err) = > {
arr[i] = { status: 'rejected'.val: err }
count += 1
if (count === promises.length) resolve(arr)
})
})
})
}
Copy the code
This code, although there is no problem logically, but you excellent programmers are certainly not pleasing to the eye, how can there be two sections of repeated code pinch, no, we have to encapsulate.
Promise.MyAllSettled = function (promises) {
let arr = [],
count = 0
return new Promise((resolve, reject) = > {
const processResult = (res, index, status) = > {
arr[index] = { status: status, val: res }
count += 1
if (count === promises.length) resolve(arr)
}
promises.forEach((item, i) = > {
Promise.resolve(item).then(res= > {
processResult(res, i, 'fulfilled')},err= > {
processResult(err, i, 'rejected')})})})}Copy the code
As the saying goes: Take two steps before you get sick. As usual, run a few cases for the code.
The test case
// All Promise instances succeed
Promise.MyAllSettled([p1, p2, p3])
.then(res= > console.log(res))
.catch(err= > console.log(err))
/ / /
// { status: 'fulfilled', value: 'p1' },
// {status: 'depressing ', value:' P2 delay one second '},
// {status: 'depressing ', value:' P3 delay two seconds'}
// ]
// There is a MyAllSettled failure
Promise.allSettled([p1, p2, p4])
.then(res= > console.log(res))
.catch(err= > console.log(err))
/ / /
// { status: 'fulfilled', value: 'p1' },
// {status: 'depressing ', value:' P2 delay one second '},
// { status: 'rejected' , value: 'p4 rejected' }
// ]
// All MyAllSettled failed
Promise.allSettled([p4, p5])
.then(res= > console.log(res))
.catch(err= > console.log(err))
/ / /
// { status: 'rejected', reason: 'p4 rejected' },
// {status: 'rejected', reason: 'p5 Rejected delay 1.5sec '}
// ]
Copy the code
So, done, I can proudly say to my mother: “Mom, I’m not afraid of Promise. All.
conclusion
This bytefly book interview is a great opportunity for me to experience the feeling of being a big company for the first time, and there may be grumpy brother to say: “This is the bytefly interview question? You are the article to deceive praise.” Harm, there is no way, mainly I am too vegetables, from the code I do not know what to now front-end learners, you come to the right week in August, the level is really more times, the interviewer is more kind, did not embarrass me, ask questions are more basic. Thanks to the byte team and the front end for this inclusive and progressive environment. I will sum up this interview well and try my best to improve myself. Come on!
Refer to the article
An interview went cold because I couldn’t fulfill my Promise. All – Nuggets (juejin. Cn)
Promise Objects – Getting Started with ECMAScript 6 (ruanyifeng.com)