Promise.all
Promise. All methods
- Receive an array of Promises
- Return a Promise with
p
The cache
After all the promises passed to promise.all are fulfilled, P follows suit and returns an array of the results of each Promise fulfilled in incoming order
However, as soon as a Promise is rejected, P will immediately identify the rejection as the reason for the rejection of the Promise.
When multiple requests are made asynchronously at the same time, that is, in parallel, all is used
let p1 = new Promise((resolve, reject) = > {
setTimeout((a)= > {
resolve('p1')},1000);
})
let p2 = new Promise((resolve, reject) = > {
setTimeout((a)= > {
resolve('p2')},2000);
})
// Prmose.all
console.time('cost')
Promise.all([p1, p2]).then(data= > {
console.log(data);
console.timeEnd('cost')})Copy the code
The output is
[ 'p1'.'p2' ]
cost: 2026.419ms
Copy the code
Code implementation
The use of the call is through promise.all, indicating that the method is on the class, not the instance, so static is used instead
class Promise{
/ /...
static all(proArr) {
return new Promise((resolve, reject) = > {
// ...}}})Copy the code
What we end up returning is an array of the values returned by each promise in proArr, stored in the order promised
So we set an array ret = [] to cache the data
We iterate through proArr to implement the promise in it
static all(proArr) {
return new Promise((resolve, reject) = > {
let ret = []
let done = (i, data) = > {
ret[i] = data
}
for (let i = 0; i < proArr.length; i++) {
proArr[i].then(data= > done(i,data) , reject)
}
})
}
Copy the code
Here we need a helper function, done, to do the saving for each successful promise return
Then why not just be direct
proArr[i].then(data= > ret[i] = data, reject)
Copy the code
Because we also need a variable to tell us if the RET is full
When it’s full, we send resolve(ret)
static all(proArr) {
return new Promise((resolve, reject) = > {
let ret = []
let count = 0
let done = (i, data) = > {
ret[i] = data
if(++count === proArr.length) resolve(ret)
}
for (let i = 0; i < proArr.length; i++) {
proArr[i].then(data= > done(i,data) , reject)
}
})
}
Copy the code
Why use a count variable, count? So let’s write it the wrong way without using count
Easy wrong points
This is where bugs come in
static all(proArr) {
return new Promise((resolve, reject) = > {
let ret = []
let done = (i, data) = > {
ret[i] = data
if(i === proArr.length - 1) resolve(ret)
}
for (let i = 0; i < proArr.length; i++) {
proArr[i].then(data= > done(i,data) , reject)
}
})
}
Copy the code
We use I equal to proArr. Length-1 as the trigger condition when the data is full
It looks like once we’ve executed the last promise of proArr we’ll execute resolve(ret)
This is because you don’t understand what promise. then means, and then methods bind methods to promises
The bound method is not executed immediately, but after the then promise succeeds or fails
So if we write it this way, if proArr[0] takes 5s to complete, that is, 5 seconds to execute
done = (0, data) = > {
ret[0] = data
if(i === proArr.length - 1) resolve(ret)
}
Copy the code
So proArr[2] is done in 1 second, so it’s executed in 1 second
done = (2, data) = > {
ret[2] = data
if(i === proArr.length - 1) resolve(ret)
}
Copy the code
Resolve (ret) proArr. Length -1 = 2
However, we know that proArr[0] has not yet been executed, i.e. we have not yet added data to RET [0]
That’s why count is used, ++count is executed when any of the proArr data is filled in
Resolve (ret) if ++count === proarr. length
Currie,
So the requirements above are pretty good for currie
static all(proArr) {
return new Promise((resolve, reject) = > {
let done = (function (len, cb) {
const ret = []
let count = 0
return function (i, data) {
ret[i] = data
if (++count === len) cb(ret)
}
})(proArr.length, resolve)
for (let i = 0; i < proArr.length; i++) {
proArr[i].then(data= > done(i, data), reject)
}
})
}
Copy the code
Of course it looks the same, of course, because if we write it this way, we can move the function out, and then the logic is clear
Promise{
// ...
static all(proArr) {
return new Promise((resolve, reject) = > {
let done = currying(proArr.length, resolve)
for (let i = 0; i < proArr.length; i++) {
proArr[i].then(data= > done(i, data), reject)
}
})
}
}
function currying(len, cb) {
const ret = []
let count = 0
return function (i, data) {
ret[i] = data
if (++count === len) cb(ret)
}
}
Copy the code
Promise.race
Like all, it accepts an array of promise objects.
The difference is that the result returns the promise data that is returned first, which in this case is the single data that is returned first. It’s kind of like a competition. Whoever gets there first gets hired.
let p1 = new Promise((resolve, reject) = > {
setTimeout((a)= > {
resolve('p1')},1000);
})
let p2 = new Promise((resolve, reject) = > {
setTimeout((a)= > {
resolve('p2')},2000);
})
// Promise.race
console.time('cost')
Promise.race([p1, p2]).then(data= > {
console.log(data);
console.timeEnd('cost')})Copy the code
The output is
p1
cost: 1014.655ms
Copy the code
When the called interface is unstable, we can fetch more than one, and use whichever one we get first.
We can also use it as a timer for promise, and if we don’t meet the deadline, we do a Reject
let p2 = new Promise((resolve, reject) = > {
setTimeout((a)= > {
resolve('p2')},2000);
})
function tiemout(delay) {
return new Promise((resolve, reject) = > {
setTimeout((a)= > {
reject('tiemout') }, delay); })}Promise.race([p2, tiemout(500)]).then(res= > {
console.log(res);
}).catch(err= > {
console.log(err);
})
Copy the code
If p2 does not receive data after 500ms, timout executes reject and timeout
And that’s easy to implement
static race(promiseAry) {
return new Promise((resolve, reject) = > {
for (let i = 0; i < promiseAry.length; i++) {
promiseAry[i].then(resolve, reject)
}
})
}
Copy the code
The promise state can only be changed once, that is, resolve and Reject can only be implemented once. We put resolve and Reject methods in promie into the success or failure callback of each promise in the promiseAry. Resolve and Reject are called when either of them succeeds or fails, and once called, they are never called again.
catch && resolve && reject
catch(onRejected) {
return this.then(null, onRejected)
}
static resolve(value) {
return new Promise((resolve, reject) = > resolve(value))
}
static reject(reason) {
return new Promise((resolve, reject) = > reject(reason))
}
Copy the code
So the above implementation is pretty simple, there’s nothing to talk about, there’s a catch, right
When we write “then”, we have two parameters, one success and one failure, so it is easy to confuse, so it is a practice to write only the success function in the “then” method, and then add a catch to handle the failure
Promise.reject('failure')
.then(data= > { console.log(data) })
.catch(reason= > { console.log(reason) })
Copy the code
If rejected is not a function, it will throw the error back.
The source code
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Circular reference'));
}
let then
let called = false
if (x instanceof Promise) {
if (x.status == PENDING) {
x.then(
y= > resolvePromise(promise2, y, resolve, reject),
r => reject(r)
)
} else x.then(resolve, reject);
} else if(x ! =null && ((typeof x == 'object' || typeof x == 'function'))) {
try {
then = x.then;
if (typeof then == 'function') {
then.call(
x,
y => {
// Prevent promise from executing both successful and failed callbacks
// If promise2 has already succeeded or failed, it is no longer processed
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
r => {
// Prevent promise from executing both successful and failed callbacks
// If promise2 has already succeeded or failed, it is no longer processed
if (called) return;
called = true;
reject(r);
});
} else{ resolve(x); }}catch (e) {
if (called) return;
called = true; reject(e); }}else{ resolve(x); }}// function gen(times, cb) {
// let ret = []
// let count = 0
// return function (i, data) {
// ret[i] = data
// if (++count === times) {
// cb(ret)
/ /}
/ /}
// }
class Promise {
constructor(executor) {
// Set the state
this.status = PENDING
this.value = undefined
// Define the callback array to execute after the store succeeds
this.onResolvedCallbacks = []
// Define an array of callbacks to execute after a failure
this.onRejectedCallbacks = []
let resolve = data= > {
let timer = setTimeout((a)= > {
clearTimeout(timer)
if (this.status === PENDING) {
this.status = FULFILLED
this.value = data
this.onResolvedCallbacks.forEach(cb= > cb(this.value))
}
})
}
let reject = reason= > {
let timer = setTimeout((a)= > {
clearTimeout(timer)
if (this.status === PENDING) {
this.status = REJECTED
this.value = reason
this.onRejectedCallbacks.forEach(cb= > cb(this.value))
}
})
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value;
onRejected = typeof onRejected == 'function' ? onRejected : reason= > { throw reason };
let promise2
if (this.status === FULFILLED) {
promise2 = new Promise((resolve, reject) = > {
let timer = setTimeout((a)= > {
clearTimeout(timer)
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
if (this.status === REJECTED) {
promise2 = new Promise((resolve, reject) = > {
let timer = setTimeout((a)= > {
clearTimeout(timer)
try {
let x = onRejected(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
if (this.status === PENDING) {
promise2 = new Promise((resolve, reject) = > {
this.onResolvedCallbacks.push(value= > {
try {
let x = onFulfilled(value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
this.onRejectedCallbacks.push(reason= > {
try {
let x = onRejected(reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
return promise2
};
catch(onRejected) {
return this.then(null, onRejected)
}
static resolve(value) {
return new Promise((resolve, reject) = > resolve(value))
}
static reject(reason) {
return new Promise((resolve, reject) = > reject(reason))
}
// static all(promiseAry) {
// return new Promise((resolve, reject) => {
// let done = gen(promiseAry.length, resolve)
// for (let i = 0; i < promiseAry.length; i++) {
// promiseAry[i].then(
// data => { done(i, data) },
// reject)
/ /}
/ /})
// }
static all(promiseAry) {
return new Promise((resolve, reject) = > {
let ret = []
let count = 0
for (let i = 0; i < promiseAry.length; i++) {
promiseAry[i].then(
data= > {
ret[i] = data
if (++count === promiseAry.length) {
resolve(ret)
}
},
reason => reject(reason)
)
}
})
}
static race(promiseAry) {
return new Promise((resolve, reject) = > {
for (let i = 0; i < promiseAry.length; i++) {
promiseAry[i].then(resolve, reject)
}
})
}
}
/ / test
Promise.deferred = Promise.defer = function () {
var defer = {};
defer.promise = new Promise(function (resolve, reject) {
defer.resolve = resolve;
defer.reject = reject;
})
return defer;
}
try {
module.exports = Promise
} catch (e) {
}
Copy the code