What is Promise?
- A Promise is a function that executes immediately, as soon as it’s new
- Promise has three states: Pending, depressing and Rejected
- Promise has two parameters, resolve on success and reject on failure.
- The value of resolve, which follows the previous success, is passed to the result of then, and the value of reject, which follows the previous failure, is passed to the next reject
- A Promise state cannot be changed once it changes, and a resolve or reject state cannot be changed
- The Promise chain call returns a new Promise each time
- If a Promise returns a normal value (non-promise non-throw), value penetration occurs
Promise executed immediately
class Promise {
construcotr(executor){ executor(); }}module.exprots = Promise;
Copy the code
Promise3 kind of state
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
constructor(executor){
this.status = PENDING; executor(); }}Copy the code
Promise2 parameters
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
constructor(executor){
this.status = PENDING; // Default pending state
this.value = null; // The result of success
this.reason = null; // The result of a failure
const resolve = (value) = > {
this.value = value;
}
const reject = (reason) = > {
this.reason = reason; } executor(resolve,reject); }}Copy the code
The state of the Promise cannot be changed
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
constructor(executor){
this.status = PENDING; // Default pending state
this.value = null; // The result of success
this.reason = null; // The result of a failure
const resolve = (value) = > {
// Resolve can only be changed from a state to a pending state
if(this.status === PENDING) {
this.value = value;
this.status = FULFILLED; }}const reject = (reason) = > {
if(this.status === ONREJECTED){
this.reason = reason;
this.status = ONREJECTED; } } executor(resolve,reject); }}Copy the code
Promise’s then method
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
constructor(executor){
this.status = PENDING; // Default pending state
this.value = null; // The result of success
this.reason = null; // The result of a failure
this.successCb = []; // The event queue after success
this.failCb = []; // Event queue after failure
const resolve = (value) = > {
// Resolve can only be changed from a state to a pending state
if(this.status === PENDING) {
this.value = value;
this.status = FULFILLED; }}const reject = (reason) = > {
if(this.status === ONREJECTED){
this.reason = reason;
this.status = ONREJECTED;
}
}
executor(resolve,reject);
},
// Then has two parameters: onFulfiled after success and onRejected after failure
then(onfulfiled,onrejected) {
// If the Promise state is successful, the successful callback can be executed
if(this.status === FULFILLED){
onfulfiled();
}
if(this.status === ONREJECTED) {
onrejected();
}
if(this.status === PENDING) {
}
}
}
Copy the code
Solve the asynchrony problem in Promise’s then method
With the publish-subscribe model, events that need to be executed are put into an event queue in THEN and called together in resolve or Reject
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
constructor(executor){
this.status = PENDING; // Default pending state
this.value = null; // The result of success
this.reason = null; // The result of a failure
this.successCb = []; // The event queue after success
this.failCb = []; // Event queue after failure
const resolve = (value) = > {
// Resolve can only be changed from a state to a pending state
if(this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
this.successCb.forEach((fn) = >fn()); Publish asynchronous events previously subscribed to when // resolve}}const reject = (reason) = > {
if(this.status === ONREJECTED){
this.reason = reason;
this.status = ONREJECTED;
this.failCb.forEach(fn= > fn());
}
}
executor(resolve,reject);
},
// Then has two parameters: onFulfiled after success and onRejected after failure
then(onfulfiled,onrejected) {
// If the Promise state is successful, the successful callback can be executed
if(this.status === FULFILLED){
this.successCb.push(() = >{ onfulfiled(); })}if(this.status === ONREJECTED) {
this.failCb.push(() = >{ onrejected(); })}if(this.status === PENDING) {
PromisePENDING: // If a Promise is executed as an asynchronous event, the PromisePENDING state indicates that the Promise is executed until the asynchronous event is executed
this.successCb.push(() = >{
onfulfiled();
})
this.failCb.push(() = >{ onrejected(); })}}}Copy the code
The chain call to Promise
Unlike Jquery, which returns this, Promise implements the chained call by returning a new Ppromsie instance
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
constructor(executor){
this.status = PENDING; // Default pending state
this.value = null; // The result of success
this.reason = null; // The result of a failure
this.successCb = []; // The event queue after success
this.failCb = []; // Event queue after failure
const resolve = (value) = > {
// Resolve can only be changed from a state to a pending state
if(this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
this.successCb.forEach((fn) = >fn()); Publish asynchronous events previously subscribed to when // resolve}}const reject = (reason) = > {
if(this.status === ONREJECTED){
this.reason = reason;
this.status = ONREJECTED;
this.failCb.forEach(fn= > fn());
}
}
executor(resolve,reject);
},
// Then has two parameters: onFulfiled after success and onRejected after failure
then(onfulfiled,onrejected) {
const promise2 = new Promise((resolve,reject) = > {
// If the Promise state is successful, the successful callback can be executed
if(this.status === FULFILLED){
this.successCb.push(() = > {
// Resvole (x) passes the value returned after the last success to the next Promsie's resolve
// If you write it like this, there is no way to get Promise2 in a resolvePromise, so use the next Promsise
// the process is wrapped in asynchronous functions
setTimeout(() = > {
try {
let x = onfulfiled(this.value);
resolvePromsie(x,promise2,resolve,reject);
} catch(err) { reject(err); }},0)})}if(this.status === ONREJECTED) {
this.failCb.push(() = > {
setTimeout(() = >{
try {
let x = onrejected(this.reason);
resolvePromsie(x,promise2,resolve,reject);
} catch(err) { reject(err); }},0)})}if(this.status === PENDING) {
this.successCb.push(() = > {
setTimeout(() = > {
try {
let x = onfulfiled(this.value);
resolvePromsie(x,promise2,resolve,reject);
} catch(err) { reject(err); }},0)})this.failCb.push(() = > {
setTimeout(() = > {
try {
let x = onrejected(this.reason);
resolvePromsie(x,promise2,resolve,reject);
} catch(err) { reject(err); }},0)})}});returnpromise2; }}function resolvePromsie(x,promsie2,resolve,reject){
// If the last return value x is the same reference as promise2, there is a self-execution situation
if(x == promise2){
return reject(new Error('type error'));
}
if((typeofx ! = =null && typeof x == 'object') | |typeof x === 'function') {try{
let then = x.then;
// If Promsie was returned last time, the recursion continues, calling then with the current x method,
if(typeof then === 'function'){
then.call(x,(y) = > {
resolvePromsie(y, promsie2,resovle,reject);
},(r) = > {
reject(r)
})
} else {
// Resolve if it is a normal valueresolve(x); }}catch(err) {
reject(err)
}
} else{ resolve(x); }}Copy the code
Resolve or reject in a Promise is still Promsie
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
constructor(executor){
this.status = PENDING; // Default pending state
this.value = null; // The result of success
this.reason = null; // The result of a failure
const resolve = (value) = > {
// If value at this point is still Pormise, then the then method of value is still called
if(value instanceof Promsie){
value.then(resolve,reject);
}
if(this.status === PENDING) {
this.value = value;
this.status = FULFILLED; }}const reject = (reason) = > {
// If the type of Reason is still Pormise, then reason's then method is still called
if(reason instanceof Promise){
reason.then(resolve,reject);
}
if(this.status === ONREJECTED){
this.reason = reason;
this.status = ONREJECTED; } } executor(resolve,reject); }}Copy the code
Full version implementation
Resolve or reject in a Promise is a normal value
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
constructor(executor){
this.status = PENDING; // Default pending state
this.value = null; // The result of success
this.reason = null; // The result of a failure
this.successCb = []; // The event queue after success
this.failCb = []; // Event queue after failure
const resolve = (value) = > {
// Resolve can only be changed from a state to a pending state
if(this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
this.successCb.forEach((fn) = >fn()); Publish asynchronous events previously subscribed to when // resolve}}const reject = (reason) = > {
if(this.status === ONREJECTED){
this.reason = reason;
this.status = ONREJECTED;
this.failCb.forEach(fn= > fn());
}
}
executor(resolve,reject);
},
// Then has two parameters: onFulfiled after success and onRejected after failure
then(onfulfiled,onrejected) {
// If the last return value x was a normal value, worth penetration will occur
onfulfiled = typeof x == 'object' ? onfulfiled : v= >v;
onrejected = typeof x == 'object' > onrejected : reject(){throw new Error(a)};const promise2 = new Promise((resolve,reject) = > {
// If the Promise state is successful, the successful callback can be executed
if(this.status === FULFILLED){
this.successCb.push(() = > {
// Resvole (x) passes the value returned after the last success to the next Promsie's resolve
// If you write it like this, there is no way to get Promise2 in a resolvePromise, so use the next Promsise
// the process is wrapped in asynchronous functions
setTimeout(() = > {
try {
let x = onfulfiled(this.value);
resolvePromsie(x,promise2,resolve,reject);
} catch(err) { reject(err); }},0)})}if(this.status === ONREJECTED) {
this.failCb.push(() = > {
setTimeout(() = >{
try {
let x = onrejected(this.reason);
resolvePromsie(x,promise2,resolve,reject);
} catch(err) { reject(err); }},0)})}if(this.status === PENDING) {
this.successCb.push(() = > {
setTimeout(() = > {
try {
let x = onfulfiled(this.value);
resolvePromsie(x,promise2,resolve,reject);
} catch(err) { reject(err); }},0)})this.failCb.push(() = > {
setTimeout(() = > {
try {
let x = onrejected(this.reason);
resolvePromsie(x,promise2,resolve,reject);
} catch(err) { reject(err); }},0)})}});returnpromise2; }}function resolvePromsie(x,promsie2,resolve,reject){
// If the last return value x is the same reference as promise2, there is a self-execution situation
if(x == promise2){
return reject(new Error('type error'));
}
if((typeofx ! = =null && typeof x == 'object') | |typeof x === 'function') {try{
let then = x.then;
// If Promsie was returned last time, the recursion continues, calling then with the current x method,
if(typeof then === 'function'){
then.call(x,(y) = > {
// The return value y after the last success is passed to the next handler
resolvePromsie(y, promsie2,resovle,reject);
},(r) = > {
reject(r)
})
} else {
// Resolve if it is a normal valueresolve(x); }}catch(err) {
reject(err)
}
} else{ resolve(x); }}Copy the code
The chain-call application of Promise
1. If the current promsie does not return a promise, the success or failure value will be passed to the outer THEN, and the success of the outer THEN will also be entered
function read(. args) {
return new Promise((resolve,reject) = >{ fs.readFile(... args,(err,data) = > {
if(err) console.log(err)
resolve(data)
})
})
}
read('./name.txt'.'utf8').then(data= > {
return 100;
},err= >{
console.log(err)
})
.then((data) = > {
console.log(data)
})
Copy the code
- If the read succeeds, it is passed into the data of the outer then
- If the read fails, console.log(err) returns undefined or passes undefined to data
2. If the current promise execution fails and an exception is thrown, the current promise fails. If the current promise execution does not fail, the outer promise fails
read("./name1.txt").then((res) = > {
throw new Error('err')},(err) = > {
console.log("err1",err)
}).then(res= > {
console.log(res)
},(err) = > {
console.log("err2",err)
}).catch(err= > {
console.log('catch',err)
})
Copy the code
- If a Promise is currently returned, the result of the execution of the current Promise is considered the success or failure of the next THEN’s then
read("./name.txt"."utf8").then((res ) = > {
return read("./age.txt".'utf8')},err= > {
console.log("err1",err)
}).then(data= > {
console.log('s',data)
},(err) = > {
console.log('err2',err)
})
Copy the code
When does the current THEN end and the next THEN fail?
- Then throws an exception
- The returned promise execution error (in chestnut 3, there was an error reading the age file) is caught by the outer err2