One, foreword
As a frequent interview question —- write a Promise that meets the Promise+ specification. At the beginning is meng, completely without train of thought, but read a lot of people’s various articles have their own train of thought.
In fact, after several handwritten promises in line with the standard, many previous doubts about the promise implementation were solved one by one, and I felt suddenly enlightened. In fact, WHAT I said was that when I did the event loop problem, I would be silly when I met the promise. But a closer look at Promise clears up a lot of questions.
Two, about a Promise to have what points to pay attention to, according to others’ articles, summarize (refer to others’ ideas and expand to add some of their own opinions)
-
- When a New Promise is passed, an executor executor executes immediately
-
- Executor accepts two arguments, resolve and Reject
-
- Promise can only go from pending to rejected, or from pending to depressing
-
- Once a promise’s status is confirmed, it doesn’t change
-
- This is a big pity. Promise has then method. Then receives two parameters, which is onFulfilled, and onRejected, which promise fails
-
- If the promise is successful when calling THEN, ondepressing will be performed and the promise value will be passed in as a parameter. If the promise has failed, then execute onRejected and pass in the reason why the promise failed. If the state of the Promise is pending, ondepressing and onRejected functions need to be stored. After the state is determined, the corresponding functions will be executed successively (release and subscribe).
-
- The onFulfilled and onRejected parameters of then can be default
-
- A promise can be then multiple times, and the then method of a promise returns a promise
-
- This is a big pity. If then returns a result, this result will be passed as a parameter to the successful ondepressing of the next THEN.
-
- If an exception is thrown in THEN, it is passed as an argument to the onRejected callback of the next THEN.
-
- If then returns a promise, then you need to wait for that promise, then you need to wait for that promise to complete. If the promise succeeds, then the next THEN succeeds, and if it fails, then the next THEN fails
Three, hand lift promise
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function myPromise(excutor) {
let self = this;
// A promise should have these five values
self.status = PENDING;
self.value = null;
self.reason = null;
// It needs to be stored when the state is always PENDING
self.onFulfilledCallBacks = [];
self.onRejectedCallBacks = [];
// excutor resolve, value is the value to be passed
function resolve(value) {
// Avoid multiple resolve
if (self.status === PENDING) {
self.value = value;
self.status = FULFILLED;
self.onFulfilledCallBacks.forEach(fn= >fn()); }}Reject (reject); reject (reject); reject (reject)
function reject(reson) {
// Avoid multiple reject
if (self.status === PENDING) {
self.reason = reson;
self.status = REJECTED;
self.onRejectedCallBacks.forEach(fn= >fn()); }}// Excutor executes immediately
try {
excutor(resolve, reject);
} catch(e) {
reject(e);
}
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
// Because ondepressing, onRejected can default, so at the beginning we should judge whether it is an executable function
// ondepressing if this is fulfilled by default, a function that returns the parameters will be executed
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value;
// onRejected Defaults to a function that throws Reason
onRejected = typeof onRejected === 'function' ? onRejected : reason= > { throw reason };
// Since the then function is itself a promise, declare a new promise
let self = this;
let promise2 = new myPromise((resolve, reject) = > {
// The execution succeeded
if (self.status === FULFILLED) {
// Ondepressing will be implemented asynchronously. Here is the simulation with settimeout. In fact, promise is implemented asynchronously in the V8 engine
setTimeout(() = > {
try {
// x is the return value of ondepressing
let x = onFulfilled(self.value);
// Recursively call the next then (chain call)
resolvePromise(promise2, x, resolve, reject);
} catch(e) {
reject(e)
}
}, 0);
}
// Execute failed state
if (self.status === REJECTED) {
setTimeout(() = > {
try {
// x is returned by Reject
let x = onRejected(self.reason);
// Recursively call the next then (chain call)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0);
}
// Execute the wait state
if (self.status === PENDING) {
// If it is pending, store it first
self.onFulfilledCallBacks.push(() = > {
setTimeout(() = > {
try {
// x is the return value of ondepressing
let x = onFulfilled(self.value);
// Recursively call the next then (chain call)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0);
})
self.onRejectedCallBacks.push(() = > {
setTimeout(() = > {
try {
// x is returned by Reject
let x = onRejected(self.reason);
// Recursively call the next then (chain call)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0); })}})return promise2;
}
function resolvePromise(promise2, x, resolve, reject) {
let self = this;
// If the call is promise2 itself, then it is a circular call
if (promise2 === x) {
return reject(new TypeError('chaining cycle'));
}
let called;
if (typeof x === 'object' && x || typeof x === 'function') {
ResolvePromise = resolvePromise = resolvePromise = resolvePromise = resolvePromise
try {
let then = x.then;
if (typeof then === 'function') {
console.log('x as the promise -- -- -- -- -- -')
then.call(x, y= > {
// There can only be one final state
if (called) return;
called = true;
// Continue the recursion
resolvePromise(promise2, y, resolve, reject);
}, r= > {
// There can only be one final state
if (called) return;
called = true; reject(r); })}else {
console.log('x is valued if the value is function or x. teng is not function ------')
// There can only be one final state
if (called) return;
called = true; resolve(x); }}catch(e) {
// There can only be one final state
if (called) return;
called = true; reject(e); }}else {
console.log('x is undefined or an explicit value ------') resolve(x); }}Copy the code
Follow-up supplementary examples.. Understand code examples