1 Implement your own Promise class and bind this
class Yu {
static PENDING = "pending";
static FUIFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.state = YU.PENDING;
this.value = null;
executor(this.resolve, this.reject);
}
resolve(value) {}
reject(reason){}}let p = new Yu((resolve, reject) = > {
resolve(1);
});
console.log(p);
Copy the code
An error will be reported if you do not bind this, because es6 classes enable strict mode by default. To avoid this error, use bind to bind this
executor(this.resolve.bind(this), this.reject.bind(this));
Copy the code
While resolve reject synchronously overwrite the previous state, we expect the state to change from Pending to Rejected or pending to depressing. The following is solved by state protection
State protection and handling of executor exception catching
State protection is a simple process: Resolve reject, reject
resolve(value) {
if (this.state === Yu.PENDING) {
this.state = Yu.FUIFILLED;
this.value = value; }}reject(reason) {
if (this.state === Yu.PENDING) {
this.state = Yu.REJECTED;
this.value = reason; }}Copy the code
When we use it this way, there may be situations like this
new Yu((resolve, reject) = > {
// Use an incorrect variable
console.log(bbb);
// Or actively throw an error
throw 2222;
//
});
Copy the code
We all need to do error handling for executors, internally using a try catch, and internally modifying the state inside the catch
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
Copy the code
That will do
3 then the basic pending depressing rejected
- Promises/A+ The specification states that you must provide a then method that accepts two parameters, onFulfilled and onRejected,
then(onFulfilled, onRejected)
The first argument is a successful callback and the second argument is a failed callback - Both parameters are optional, meaning
.then()
Then value penetration, which returns the value inside the current Promise instance - This is a big pity. When ondepressing is a function, it can be called only when the current state is very depressing.
- Ondepressing is a function, which must be called only when the current state is Rejected. This can not be called many times before.
- Then can be called multiple times on the same Promise instance
- Then must return a new Promise instance
promise2 = promise1.then(onFulfilled, onRejected)
Then is a prototypical method that takes two callback functions as arguments.
then(onFulfilled, onRejected) {
// The first function passed in is executed and the value on the instance is passed to the current function
onFulfilled(this.value);
}
Copy the code
This will be a big pity. This will be a big pity when resolve(‘success’) is called internally to save SUCCss on the value attribute of the instance and change the current state to the success state. This is a big pity. When executing the ondepressing method, pass this. Value, which is success, to ondepressing, so that when you call it again, output the parameter value, which is the argument, success.
let p = new Yu((resolve, reject) = > {
resolve("success");
}).then(val= > {
console.log(val); //success
});
Copy the code
But when we comment resolve, there should be no output, and there is still an output, so we can’t just come up and execute the successful method in then. Instead, we should execute it under certain circumstances. What happens? This is the fulfilled request. Similarly, the other two cases are also similar. The code is modified as follows:
then(onFulfilled, onRejected) {
//1 Check todo for two parameters
When and when are two passed functions executed?
this.state === Yu.FUIFILLED && onFulfilled(this.value);
this.state === Yu.REJECTED && onRejected(this.value);
if (this.state === Yu.PENDING) {
// Save the function temporarily because you don't know when it succeeds or fails
}
//3 Return a new Promise instance why do I need to return a new Promise instance? Because I can support chain calls then is a recursive function that calls itself every time so I can just return this the next time I use then by looking for the then method on the prototype chain
// Can also implement the chain call? So why not return this directly instead of using a new constructor to get a new instance? Because you need to pass the last state
// And the return cannot be the same as the last instance, if the same should give an error message
}
Copy the code
When called, notice that the then method takes two callback functions as arguments: the first is the successful function and the second is the failed function. If the first or second parameter is not passed, do not report the error, and then we need to do parameter processing in the then
then(onFulfilled, onRejected) {
//1 Check the two parameters
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () = > {};
onRejected = typeof onRejected === "function" ? onRejected : () = > {};
//2 execute only when the two functions passed in are corresponding states
this.state === Yu.FUIFILLED && onFulfilled(this.value);
this.state === Yu.REJECTED && onRejected(this.value);
if (this.state === Yu.PENDING) {
// Save the function temporarily because you don't know when it succeeds or fails}}Copy the code
When handling errors, catch exceptions as well. So you need to refine the error handling function to throw the exception itself
//1 Check the two parameters
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () = > {};
onRejected =
typeof onRejected === "function"
? onRejected
: err= > {
throw err;
};
Copy the code
The result of the call could be something like this
let p = new Yu((resolve, reject) = > {
resolve("success");
}).then(
val= > {
console.log(val);
}
// The second argument is not passed, because then is processed internally
// reason => {
// console.log(reason);
// }
);
Copy the code
Or you could call it this way
let p = new Yu((resolve, reject) = > {
reject("Failure");
}).then(
// The first argument is not a function and does not return an error because then is handled internally
null.reason= > {
console.log(reason); });Copy the code
Another problem is that if there are mistakes in the “onFulfilled” and “onRejected”, we also need to deal with the “try catch” internally
//2 execute only when the two functions passed in are corresponding states
if (this.state === Yu.FUIFILLED) {
try {
onFulfilled(this.value);
} catch (e) {
onRejected(this.value); }}if (this.state === Yu.REJECTED) {
try {
onRejected(this.value);
} catch (e) {
onRejected(this.value); }}Copy the code
Another detail is, is the resovle in the New Promise executed synchronously or asynchronously? We can take a look at the normal promsie output order
let p2 = new Promise((resolve, reject) = > {
console.log(1111);
resolve("Success");
console.log(2222);
}).then(val= > console.log(val));
Copy the code
So we’ll make resolve Reject asynchronous, which we can emulate with setTimeout
const fakeMicroTask = (cb, timer = 1000) = > setTimeout(cb, timer);
//2 execute only when the two functions passed in are corresponding states
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() = > {
try {
onFulfilled(this.value);
} catch (e) {
onRejected(this.value); }}); }if (this.state === Yu.REJECTED) {
fakeMicroTask(() = > {
try {
onRejected(this.value);
} catch (e) {
onRejected(this.value); }}); }Copy the code
If a new Promise calls resolve or reject asynchronously, let’s look at the normal Promise execution order:
let p2 = new Promise((resolve, reject) = > {
console.log(1111);
setTimeout(() = > {
resolve("Success");
}, 1000);
console.log(2222);
}).then(val= > console.log(val));
console.log("first");
// Output sequence
/ / 1111
/ / 2222
//first
// Output succeeded after one second
Copy the code
So we’re going to handle resolve asynchronously, and we’re going to handle pending, because the state is pending at first, and it’s going to wait a second before it changes
const fakeMicroTask = (cb, timer = 1000) = > setTimeout(cb, timer);
class Yu {
static PENDING = "pending";
static FUIFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.state = Yu.PENDING;
this.value = null;
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e); }}resolve(value) {
if (this.state === Yu.PENDING) {
this.state = Yu.FUIFILLED;
this.value = value;
this.callbacks.forEach(cbObj= >{ cbObj.onFulfilled(value); }); }}reject(reason) {
if (this.state === Yu.PENDING) {
this.state = Yu.REJECTED;
this.value = reason;
this.callbacks.forEach(cbObj= >{ cbObj.onRejected(reason); }); }}then(onFulfilled, onRejected) {
//1 Check the two parameters
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () = > {};
onRejected =
typeof onRejected === "function"
? onRejected
: err= > {
throw err;
};
//2 execute only when the two functions passed in are corresponding states
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() = > {
try {
onFulfilled(this.value);
} catch (e) {
onRejected(this.value); }}); }if (this.state === Yu.REJECTED) {
fakeMicroTask(() = > {
try {
onRejected(this.value);
} catch (e) {
onRejected(this.value); }}); }if (this.state === Yu.PENDING) {
// Save the function temporarily because you don't know when it succeeds or fails
this.callbacks.push({ onFulfilled, onRejected }); }}}Copy the code
Handle pending status exceptions
// There is no error handling
if (this.state === Yu.PENDING) {
// Save the function temporarily because you don't know when it succeeds or fails
this.callbacks.push({
onFulfilled,
onRejected
});
}
// Add error handling to pending state
if (this.state === Yu.PENDING) {
// Save the function temporarily because you don't know when it succeeds or fails
this.callbacks.push({
onFulfilled: value= > {
try {
onFulfilled(value);
} catch(err) { onRejected(err); }},onRejected: reason= > {
try {
onRejected(value);
} catch(err) { onRejected(err); }}}); }Copy the code
What is the following output order? :
let p = new Yu((resolve, reject) = > {
setTimeout(() = > {
resolve("success");
console.log(111);
});
}).then(value= > console.log(value), reason= > console.log(reason));
console.log("first");
Copy the code
1 first 2 success 3 111
But the normal order of promise output is
1 first 2 111 3 success
So we’re going to make a change: make it asynchronous
resolve(value) {
if (this.state === Yu.PENDING) {
this.state = Yu.FUIFILLED;
this.value = value;
fakeMicroTask(() = > {
this.callbacks.forEach(cbObj= >{ cbObj.onFulfilled(value); }); }); }}reject(reason) {
if (this.state === Yu.PENDING) {
this.state = Yu.REJECTED;
this.value = reason;
fakeMicroTask(() = > {
this.callbacks.forEach(cbObj= >{ cbObj.onRejected(reason); }); }); }}Copy the code
4 then supports chained calls
So let’s call
let p = new Yu((resolve, reject) = > {
setTimeout(() = > {
resolve("success");
console.log(111);
});
console.log(2222);
})
.then(value= > console.log(value), reason= > console.log(reason))
.then(val= > console.log(val));
Copy the code
Uncaught TypeError: Cannot read property 'then' of undefined
-
Chain call so you return a new promise
-
New promise, reject, reject does not affect then.
To implement chain calls:
then(onFulfilled, onRejected) {
//1 Check the two parameters
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () = > {};
onRejected =
typeof onRejected === "function"
? onRejected
: err= > {
throw err;
};
//3 Returns a new Promise instance
let newThen = new Yu((resolve, reject) = > {
//2 execute only when the two functions passed in are corresponding states
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() = > {
try {
onFulfilled(this.value);
} catch (e) {
onRejected(this.value); }}); }if (this.state === Yu.REJECTED) {
fakeMicroTask(() = > {
try {
onRejected(this.value);
} catch (e) {
onRejected(this.value); }}); }if (this.state === Yu.PENDING) {
// Save the function temporarily because you don't know when it succeeds or fails
this.callbacks.push({
onFulfilled: value= > {
try {
onFulfilled(value);
} catch(err) { onRejected(err); }},onRejected: reason= > {
try {
onRejected(value);
} catch(err) { onRejected(err); }}}); }});return newThen;
}
Copy the code
Then value penetration problem handling
Parameter verification directly returnsthis. The value//1 Check the two parameters
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () = > this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () = > this.value;
Copy the code
Then added promise exception handling
then(onFulfilled, onRejected) {
//1 Check the two parameters
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () = > this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () = > this.value;
// onRejected =
// typeof onRejected === "function"
/ /? onRejected
// : err => {
// throw err;
/ /};
//3.1 Create a new instance
let newPromiseInstance = new Yu((resolve, reject) = > {
//2 execute only when the two functions passed in are corresponding states
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() = > {
try {
let result = onFulfilled(this.value);
resolve(result);
} catch(e) { reject(e); }}); }if (this.state === Yu.REJECTED) {
fakeMicroTask(() = > {
try {
let result = onRejected(this.value);
// Resolve is the value returned from then onRejected
resolve(result);
} catch(e) { reject(e); }}); }if (this.state === Yu.PENDING) {
// Save the function temporarily because you don't know when it succeeds or fails
this.callbacks.push({
onFulfilled: value= > {
try {
let result = onFulfilled(value);
resolve(result);
} catch(err) { reject(err); }},onRejected: reason= > {
try {
let result = onRejected(reason);
resolve(result);
} catch(err) { reject(err); }}}); }});Return a new Promise instance
return newPromiseInstance;
}
Copy the code
Then we add a try catch to the three states, reject, and pass the error in the catch
Is the value returned in then a normal value or a new Promise?
- The state and result of the object are determined by the return value of the callback function
- If the return value is a Promise object:
- If the return value is success, the new Promise is success
- The return value fails, and new Primise is a failure
- If the return value is not a Promise object
- The new Promsie is success, and its value is the return value
Ondepressing returns the normal value, Let result = ondepressing (this.value)) this if (result instanceof Yu) is a promise instance, which will be fulfilled later. Result. then(resolve, reject) is called and the resolve, reject method is passed to the outer then.
// Success inside
if (result instanceof Yu) {
// result.then(
// value => {
// resolve(value);
/ /},
// reason => {
// // handles the return inside the rejection
// reject(reason);
/ /}
// );
// Equivalent to;
result.then(resolve, reject);
} else {
// Return normal value to change state directly
resolve(result);
}
// Even in failure
// Change pending
Copy the code
Now the then method
then(onFulfilled, onRejected) {
//1 Check the two parameters
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () = > this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () = > this.value;
// onRejected =
// typeof onRejected === "function"
/ /? onRejected
// : err => {
// throw err;
/ /};
//3.1 Create a new instance
let newThen = new Yu((resolve, reject) = > {
//2 execute only when the two functions passed in are corresponding states
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() = > {
try {
let result = onFulfilled(this.value);
if (result instanceof Yu) {
// result.then(
// value => {
// resolve(value);
/ /},
// reason => {
// // handles the return inside the rejection
// reject(reason);
/ /}
// );
// Equivalent to;
result.then(resolve, reject);
} else {
// Return normal value to change state directlyresolve(result); }}catch (e) {
onRejected(this.value); }}); }if (this.state === Yu.REJECTED) {
fakeMicroTask(() = > {
try {
let result = onRejected(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
// Return normal value to change state directlyresolve(result); }}catch (e) {
onRejected(this.value); }}); }if (this.state === Yu.PENDING) {
// Save the function temporarily because you don't know when it succeeds or fails
this.callbacks.push({
onFulfilled: value= > {
try {
let result = onFulfilled(value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
// Return normal value to change state directlyresolve(result); }}catch(err) { onRejected(err); }},onRejected: reason= > {
try {
let result = onRejected(value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
// Return normal value to change state directlyresolve(result); }}catch(err) { onRejected(err); }}}); }});Return a new Promise instance
return newThen;
}
Copy the code
A lot of this is repetitive, so you can take the same parts out and refactor the code
parse(result, resolve, reject) {
try {
// Get rid of this line because success and failure call differently externally
// let result = onFulfilled(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
// Return normal value to change state directlyresolve(result); }}catch (e) {
onRejected(this.value); }}Copy the code
Now the whole thing looks like this:
const fakeMicroTask = (cb, timer = 1000) = > setTimeout(cb, timer);
class Yu {
static PENDING = "pending";
static FUIFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.state = Yu.PENDING;
this.value = null;
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e); }}resolve(value) {
if (this.state === Yu.PENDING) {
this.state = Yu.FUIFILLED;
this.value = value;
fakeMicroTask(() = > {
this.callbacks.forEach(cbObj= >{ cbObj.onFulfilled(value); }); }); }}reject(reason) {
if (this.state === Yu.PENDING) {
this.state = Yu.REJECTED;
this.value = reason;
fakeMicroTask(() = > {
this.callbacks.forEach(cbObj= >{ cbObj.onRejected(reason); }); }); }}parse(result, resolve, reject) {
try {
// Get rid of this line because success and failure call differently externally
// let result = onFulfilled(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
// Return normal value to change state directlyresolve(result); }}catch (e) {
onRejected(this.value); }}then(onFulfilled, onRejected) {
//1 Check the two parameters
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () = > this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () = > this.value;
//3.1 Create a new instance
let newPromiseInstance = new Yu((resolve, reject) = > {
//2 execute only when the two functions passed in are corresponding states
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() = > {
this.parse(onFulfilled(this.value), resolve, reject);
});
}
if (this.state === Yu.REJECTED) {
fakeMicroTask(() = > {
this.parse(onRejected(this.value), resolve, reject);
});
}
if (this.state === Yu.PENDING) {
// Save the function temporarily because you don't know when it succeeds or fails
this.callbacks.push({
onFulfilled: value= > {
this.parse(onFulfilled(value), resolve, reject);
},
onRejected: reason= > {
this.parse(onRejected(reason), resolve, reject); }}); }});Return a new Promise instance
return newPromiseInstance;
}
let p = new Yu((resolve, reject) = > {
resolve("success");
})
.then(
value= > {
console.log("first then " + value);
return "alex from firs then ";
},
reason= > console.log(reason)
)
.then(val= > console.log("second " + val));
Copy the code
Tests chained operations in THEN and returns normal values in THEN
Any initial Promise state change requires a manual call to Resove or Reject from New Promsie to allow the state to flow
- Resolve: a successful callback in the first THEN returns the normal value. A successful callback in the second THEN prints the value returned in the first THEN
- Case 2 reject a value, the first then it failed callback returns average value inside, in the second then the success callback to print first then inside the callback returns average value inside of failure
- The first then successful callback returns a normal value, and the second then successful callback outputs the value returned by the previous THEN successful callback
- Case 4 tests pending state, which calls reject with asynchrony. The first then failure callback returns a normal value, while the second then success callback outputs the value returned by the previous THEN failure callback
Then returns the processing of a promise
All of the above deals with cases where then returns the base value, and if we return a pormise, our current version is not correct, we have to do something about it, If the result is a promise instance, pass it to the then method. If it is a promise instance, pass it to the then method. If it is a promise instance, pass it to the then method. This is a big pity.
Simplify the code inside
So I’m going to write it this way
Then rejected and pending return Promise
Rejected before renovation:
Rejected after modification:
Before modifying pending cases, handle the two cases separately:
Pending after modification:
Now the then method:
then(onFulfilled, onRejected) {
//1 Check the two parameters
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () = > this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () = > this.value;
//3.1 Create a new instance
let newPromiseInstance = new Yu((resolve, reject) = > {
//2 execute only when the two functions passed in are corresponding states
// Successful judgment and handling
if (this.state === Yu.FUIFILLED) {
// put it in an asynchronous queue
fakeMicroTask(() = > {
// Add error handling
try {
// Process the return value of then onFulfilled is an ordinary value or a new Promise
// Get the return value
let result = onFulfilled(this.value);
// The return value is an instance of Promise
if (result instanceof Yu) {
result.then(resolve, reject);
} else {
// Return a value that is not an instance of Promiseresolve(result); }}catch (e) {
// The fault-tolerant processing of the onFulfilled or onRejected function will be received in the onRejected function of the next THENreject(e); }}); }// Failure judgment and handling
if (this.state === Yu.REJECTED) {
fakeMicroTask(() = > {
try {
// Then onRejected returns a normal value or a new Promise
let result = onRejected(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else{ resolve(result); }}catch(e) { reject(e); }}); }if (this.state === Yu.PENDING) {
// Save the function temporarily because you don't know when it succeeds or fails
this.callbacks.push({
onFulfilled: value= > {
try {
// Then pending ondepressing returns a normal value or a new Promise
let result = onFulfilled(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else{ resolve(result); }}catch(e) { reject(e); }},onRejected: reason= > {
try {
// Then pending onRejected returns a normal value or a new Promise
let result = onRejected(this.value);
if (result instanceof Yu) {
result.then(resolve, reject);
} else{ resolve(result); }}catch(e) { reject(e); }}}); }});Return a new Promise instance
return newPromiseInstance;
}
Copy the code
Small refactoring of then methods
There are too many similar contents in the try catch of the above three states. We can encapsulate a small function for unified processing:
parse(result, resolve, reject) {
try {
// Get rid of this line because success and failure call differently externally
// let result = onFulfilled(this.value);
if (result instanceof Yu) {
//then calls resolve reject when a successful or failed callback returns a promise instance
result.then(resolve, reject);
} else {
// Return normal value to change state directlyresolve(result); }}catch (e) {
reject(this.value); }}Copy the code
Remove comments:
parse(result, resolve, reject) {
try {
if (result instanceof Yu) {
result.then(resolve, reject);
} else{ resolve(result); }}catch (e) {
reject(this.value); }}Copy the code
Next, replace the repeated parts as a parse function
A modified test of then that returns a promise and resolve state
Test for cases where a promise is returned from then and written incorrectly on purpose
What is the output of resovle if you place an intentionally miswritten line after it? The processing of native Primise goes like this
The result is: no processing, it will be processed before
We implemented Yu as well:
Similarly, use the parse function and continue to modify the repeats in the pending and onRejected states of then.
After the rejected:
The onRejected callback returns a new promise from the first then parameter, which is the onRejected callback
Pending state before transformation:
Modified:
Test the case for Pending Resolve
Test pending Reject
The whole then method after modifying pending:
The code is much smaller and more readable than the previous THEN method
The native Promise doesn’t handle errors in an asynchronous call to resolve, which we’ll leave out for now.
Promise returns a constraint of type
If promise and x refer to the same object, reject promise with a TypeError as the reason.
Native Promise performance:
The method in then executes asynchronously and since it is asynchronous you can get the new PRImise instance P returned by THEN
There is no processing in our own implementation, and the output looks like this:
This can be done within the parse function:
parse(newReturnedPromiseInstance, result, resolve, reject) {
//If promise and x refer to the same object, reject promise with a TypeError as the reason.
if (newReturnedPromiseInstance === result) {
throw new TypeError("Chaining cycle detected for promise");
}
try {
if (result instanceof Yu) {
result.then(resolve, reject);
} else{ resolve(result); }}catch (e) {
reject(this.value); }}Copy the code
Then make changes in then where parse is called:
Test it out and it works
5 implementation Promise. Resolve
Js es6 plus static means to define a method or property on a constructor, which you can use as a constructor. Resolve class Yu{static resolve(value) {}
The resolve Reject of the native Promise passes in a base value
Our implementation:
static resolve(value) {
return new Yu((resolve, reject) = > {
resolve(value);
});
}
Copy the code
Also consider the case where a promise object is passed in, so the code changes to:
static resolve(value) {
return new Yu((resolve, reject) = > {
if (value instanceof Yu) {
value.then(resolve, reject);
} else{ resolve(value); }}); }Copy the code
Test Yu. Resolve
6 realization Promise. Reject
In the same way Yu. Reject
static reject(reason) {
return new Yu((resolve, reject) = > {
if (reason instanceof Yu) {
reason.then(resolve, reject);
} else{ reject(reason); }}); }Copy the code
Test Yu. Reject
7 realization Promise. All
The idea is to return a new Promise and reject any failure, which is a direct then failure,
All successes are successful, so an array count is required to see if the result array is the same as the primises array passed in. If so, all results are passed as arguments to resolve
Code implementation
static all(promisesArr) {
let values = [];
return new Yu((resolve, reject) = > {
promisesArr.forEach(promise= > {
promise.then(
val= > {
values.push(val);
// resolve if it is equal
if(values.length == promisesArr.length) { resolve(values); }},reason= >{ reject(reason); }); }); }); }Copy the code
There is one failure of the test
All tests are successful
8 implementation Promise. Race
Use whoever is quick
static race(promsisesArr) {
return new Yu((resolve, reject) = > {
promsisesArr.map(promise= > {
promise.then(
value= > {
resolve(value);
},
reason= >{ reject(reason); }); }); }); }Copy the code
9 test todo after fill
Summary:
- Yu is a constructor,
- This is a pity rejected, which is the current state. The default is pending
- There is also a this.value that holds the value passed in externally
- The executor callback takes resolve, reject, and error handling. The executor callback takes resolve, reject, and reject.
- Executors are called in the constructor and are synchronized
- There is also a callbacks function on top of the constructor, which is used to hold the onFulfilled and onRejected functions, so that the resolve or reject functions can be called later
- A promise state change starts with a manual call to resolve or reject, both synchronous and asynchronous
- Yu’s prototype had the Resovle Reject THEN method on it
- The resolve method does three things:
- When the current state is pending, store the incoming value on this.value
- When the current state is pending, modify the current state as depressing
- If there is a value in the callbacks on the current instance, loop through it, retrieve the ondepressing function inside, execute it, and pass the resolve parameter to it
- The reject method does three things:
- When the current state is pending, store incoming reason on this.value
- When the current status is Pending, change the current status to Rejected
- If the current instance has a value in the callbacks, loop through it, fetch the onRejected function, execute it, and pass resolve to it
- Then method
-
Return a new Promise instance that continues using the method on the prototype chain through the prototype chain
-
Two arguments to then are processed
- Handling errors
- Handles cases where arguments are not functions
- Handle the case where the second argument throws an exception
-
There are three types of then that handle 3.1 Pending states. The resolve and REJECT callbacks are used for pending states. Execute with the loop callbacks
-3.1.1 Ondepressing is uncertain about the current state, so it will be saved to the previous callbacks. After the ondepressing return value is fulfilled, try catch will process it and determine whether the return value is an instance of Promise. If so, the then method of the result will be called. -3.1.2 onRejected = resolve,reject = reject If so, call the result's then method, pass resolve,reject, or resolve.Copy the code
3.2 The state of pity
- In asynchrony, call resolveCopy the code
3.3 Rejected status
Put it in async, call RejectCopy the code
-
A new promise returned in then cannot be processed in the next THEN, and the previous instance can only be fetched in asynchrony
-
Error handling of three states
-
Over-extraction of duplicate code
-
- The resolve method does three things:
- The Yu constructor has the All Race Resolve Reject method above it
- All: If there is one failure, the system fails. If there are multiple successes, the system succeeds. If there are multiple successes, an array is maintained internally. Each promise.then is passed a success value into the array. Finally, the two arrays are judged to be equal in length, which means success, and an array with all asynchronous success values is returned
- Race: One failure is a failure, one success is a change of status to success.
- resolve:
- The case where the parameter passed is the base value
- The argument passed in is a case of a Promise instance
- Resolve:
- The case where the parameter passed is the base value
- The argument passed in is a case of a Promise instance
- There are still some details that are not perfect in the implementation process, for example, some more detailed boundary processing is not implemented here, welcome to correct,
The complete code
<! DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<script>
const fakeMicroTask = (cb, timer = 1000) = > setTimeout(cb, timer);
class Yu {
static PENDING = "pending";
static FUIFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.state = Yu.PENDING;
this.value = null;
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e); }}resolve(value) {
if (this.state === Yu.PENDING) {
this.state = Yu.FUIFILLED;
this.value = value;
fakeMicroTask(() = > {
this.callbacks.forEach(cbObj= >{ cbObj.onFulfilled(value); }); }); }}reject(reason) {
if (this.state === Yu.PENDING) {
this.state = Yu.REJECTED;
this.value = reason;
fakeMicroTask(() = > {
this.callbacks.forEach(cbObj= >{ cbObj.onRejected(reason); }); }); }}parse(newReturnedPromiseInstance, result, resolve, reject) {
//If promise and x refer to the same object, reject promise with a TypeError as the reason.
if (newReturnedPromiseInstance === result) {
throw new TypeError("Chaining cycle detected for promise");
}
try {
if (result instanceof Yu) {
result.then(resolve, reject);
} else{ resolve(result); }}catch (e) {
reject(this.value); }}then(onFulfilled, onRejected) {
//1 Check the two parameters
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : () = > this.value;
onRejected =
typeof onRejected === "function" ? onRejected : () = > this.value;
//3.1 Create a new instance
let newPromiseInstance = new Yu((resolve, reject) = > {
//2 execute only when the two functions passed in are corresponding states
if (this.state === Yu.FUIFILLED) {
fakeMicroTask(() = > {
this.parse(
newPromiseInstance,
onFulfilled(this.value),
resolve,
reject
);
});
}
if (this.state === Yu.REJECTED) {
fakeMicroTask(() = > {
this.parse(
newPromiseInstance,
onRejected(this.value),
resolve,
reject
);
});
}
if (this.state === Yu.PENDING) {
// Save the function temporarily because you don't know when it succeeds or fails
this.callbacks.push({
onFulfilled: value= > {
this.parse(
newPromiseInstance,
onFulfilled(this.value),
resolve,
reject
);
},
onRejected: reason= > {
this.parse(
newPromiseInstance,
onRejected(this.value), resolve, reject ); }}); }});Return a new Promise instance
return newPromiseInstance;
}
static resolve(value) {
return new Yu((resolve, reject) = > {
if (value instanceof Yu) {
value.then(resolve, reject);
} else{ resolve(value); }}); }static reject(reason) {
return new Yu((resolve, reject) = > {
if (reason instanceof Yu) {
reason.then(resolve, reject);
} else{ reject(reason); }}); }static all(promisesArr) {
let values = [];
return new Yu((resolve, reject) = > {
promisesArr.forEach(promise= > {
promise.then(
val= > {
values.push(val);
// resolve if it is equal
if(values.length == promisesArr.length) { resolve(values); }},reason= >{ reject(reason); }); }); }); }static race(promsisesArr) {
return new Yu((resolve, reject) = > {
promsisesArr.map(promise= > {
promise.then(
value= > {
resolve(value);
},
reason= >{ reject(reason); }); }); }); }}/ / test Yu. All
let p1 = new Yu(resolve= > {
resolve(1);
});
let p2 = new Yu((resolve, reject) = > {
reject("Reject");
});
Yu.all([p1, p2]).then(
arrs= > {
console.log(arrs);
},
err= > {
console.log(err); });// // tests yu.resolve for passing base values
// Yu.resolve("test").then(val => {
// console.log(val);
// });
// // tests yu.resolve passed to promsie
// let p = new Yu((resolve, reject) => {
// resolve("yu succeed ");
// });
// Yu.resolve(p).then(val => {
// console.log(val);
// });
// console.log(
// Yu.reject("reject Yu ").then(null, reason => {
// console.log(reason);
/ /})
// );
// Test yu.reject for passing base values
// Yu.reject("test").then(null, val => {
// console.log(val);
// });
// // tests yu.reject for passing promsie
// let p = new Yu((resolve, reject) => {
// reject("yu 拒绝");
// });
// Yu.reject(p).then(null, err => {
// console.log(err);
// });
//test diy Promsie
// let p = new Yu((resolve, reject) => {
// setTimeout(() => {
// reject(" reject ");
/ /}, 1000);
// })
// .then(
// value => {
// console.log(value);
// return new Yu((resolve, reject) => {
// resolve("Yu first then resolve");
/ /});
/ /},
// reason => {
// console.log(reason);
// return new Yu((resolve, reject) => {
// console.log(aaaa);
// resolve("Yu first then reject");
/ /});
/ /}
/ /)
// .then(
// val => console.log(val),
// reason => {
// console.log("second then rejected function " + reason);
/ /}
/ /);
//test chain promise
// let p1 = new Yu(resolve => {
// resolve(222);
// });
// let p2 = p1.then(val => {
// return p2;
// });
// let p = new Promise((resolve, reject) => {
// resolve("111");
// });
// let p2 = p.then(val => {
// return p2;
// });
// console.log(p2);
//test promise
// let p2 = new Promise((resolve, reject) => {
// setTimeout(() => {
// console.log(AAA);
// resolve("success");
/ /}, 1000);
// })
// .then(
// val => {
// console.log(val);
// return new Promise((resolve, reject) => {
// resolve("first then resolve");
/ /});
/ /},
// reason => {}
/ /)
// .then(
// val => {
// console.log(val);
/ /},
// reason => {
// console.log(reason);
/ /}
/ /);
//test Promsie.resolve Promise.reject
// let p1 = new Promise(resolve => {
// resolve(" resolve ");
// });
// Promise.resolve(p1).then(val => {
// console.log(val);
// });
// let p2 = new Promise((resolve, reject) => {
// reject(" reject ");
// });
// Promise.reject(p2).then(
// val => {
// console.log(val);
/ /},
// reason => {
// console.log(reason);
/ /}
// );
// test Promise.all
// let p11 = new Promise(resolve => {
// resolve(111);
// });
// let p22 = new Promise((resolve, reject) => {
// // reject(2);
// resolve(222);
// });
// Promise.all([p11, p22]).then(
// arrs => {
// console.log(arrs);
/ /},
// err => {
// console.log(err);
/ /}
// );
</script>
</body>
</html>
Copy the code
Thank you
- Can see here, that is really read carefully, thank you!