JavaScript is a single-threaded language that achieves asynchronous operations by maintaining an execution stack and task queue. setTimeout and Ajax are typical examples of asynchronous operations, and Promise is a solution for asynchronous operations, used to represent the eventual completion or failure of an asynchronous operation, along with its result value.
newPromise(function(resolve, reject){/* executor */// Execution code that needs to specify the positions of the resolve and reject callbacks});
The executor is a function with two parameters: resolve and reject. When the Promise constructor is called, the executor function is immediately executed, with the resolve and reject functions passed as parameters to the executor. When the resolve and reject functions are called, they respectively change the promise's state to fulfilled or rejected. The executor typically performs some asynchronous operations internally, and once the asynchronous operation is completed, either the resolve function is called to change the promise's state to fulfilled, or the reject function is called to change the promise's state to rejected. If an error is thrown within the executor function, the promise state is rejected, and the return value of the executor function is ignored.
In essence, a Promise is a state machine, specifically a finite-state machine, where the output can be explicitly calculated based on the current input and state.
pending: Initial state, neither fulfilled nor rejected.
fulfilled: Indicates successful completion of the operation.
rejected: Indicates operation failure.
A Promise object only changes state from pending to either fulfilled or rejected. Once in the fulfilled or rejected state, the status does not change.
// Define the _Promise constructor functionfunction_Promise(fn){this.status ="pending";// Define the property to store the status // Give the initial status as pendingthis.value =null;// value of resolvethis.reason =null;// reason of rejectthis.onFulfilled =[];// Store the first callback function registered in the then methodthis.onReject =[];// Store the second callback function registered in the then methodvarhandler=funct=>{// Event handling functionif(typeof(funct)==="function"){// Only execute if it's a functionif(this.status ==="fulfilled")funct(this.value);// Execute and pass the valueif(this.status ==="rejected")funct(this.reason);// Execute and pass the reason}}// Implement the resolve callbackvarresolve=value=>{// Using arrow function mainly to bind the this keywordthis.status ="fulfilled";// Set the statusthis.value = value;// Get the resultif(value instanceof_Promise){// Check if the returned value is an instance of Promise value.onFulfilled =this.onFulfilled;// If yes, then chain call itreturn value;}setTimeout(()=>{// Use setTimeout to place the callback function in the task queue, not blocking the main thread, execute asynchronously. In reality, the promise's callback is placed in the microqueue, while the setTimeout's callback is placed in the macroqueuetry{this.onFulfilled.forEach(handler);// Hand over to the event handler}catch(e){ console.error(`Error in promise: ${e}`);// Print the exceptionreject(e);// Reject}},0)}// Implement rejectedvarreject=reason=>{// Using arrow function mainly to bind the this keywordthis.status ="rejected";// Set the statusthis.reason = reason;// Get the resultsetTimeout(()=>{// Place it in the task queuetry{this.onReject.forEach(handler);// Hand over to the event handler}catch(e){ console.error(`Error in promise: ${e}`);// Print the exception}},0)}fn(resolve, reject);// Execute}// Define then// value receives the result from the upper layer, function handles its own logic, and return it to the lower layer_Promise.prototype.then=function(onFulfilled, onRejected){ onFulfilled =typeof onFulfilled ==='function'?onFulfilled:v=> v;// Convert to a function onRejected =typeof onRejected ==='function'?onRejected:r=> r;// Convert to a functionreturnnew_Promise((resolve, reject)=>{// Return a new _Promisethis.onFulfilled.push((value)=>{// Place the callback function on onFulfilledresolve(onFulfilled(value));// Execute and pass it});this.onReject.push((value)=>{// Place the callback function on onRejectreject(onRejected(value));// Execute and pass it});})}
// Testvar promise =new_Promise(function(resolve,reject){var rand = Math.random()*2;setTimeout(function(){if(rand <1)resolve(rand);elsereject(rand);},1000)})promise.then((rand)=>{ console.log("resolve",rand);// callback for resolve},(rand)=>{ console.log("reject",rand);// callback for reject}).then(function(){// continue after resolvereturnnew_Promise(function(resolve,reject){var rand = Math.random()*2;setTimeout(function(){resolve(rand);},1000)})}).then(function(num){// continue after resolve console.log(num,"continue execution and receive parameter");return1;}).then(function(num){ console.log(num,"continue execution and receive parameter");})/*
The implemented _Promise is relatively simple
The actual Promise used is more complex, with considerations for various situations
In the example, only the Promise constructor and then are implemented. In practice, there are also implementations for catch, Promise.all, Promise.race, Promise.resolve, Promise.reject, etc.
*/