ES6 Promise is a familiar Promise, one of the solutions to asynchrony in JS
Advantages: Avoid callback hell, chain calls, function thinking is clear, logic is stronger than callback function and event publish/subscribe
Disadvantages: Poor understanding, asynchronous operations inside the Promise constructor
During this period of time, WHEN I was sorting out the interview questions, I found that the implementation of Promise could be shared separately, so I simply implemented it myself
Code cloud Address:Gitee.com/DieHunter/m…
Before we implement the full functionality, let’s look at the use of Promise and implement a simple Promise and promise.then function
Promise(executor: (resolve: (value? : any) =>void, reject: (reason? : any) =>void) = > void) :Promise<any>
Copy the code
As you can see from the above configuration tip, a Promise needs to be passed in a callback function that takes two arguments (resolve, reject), the first to call back if the asynchronous execution succeeds and the second to call back if it fails. The Promise. Then method executes a callback from the then method only if the asynchronous function is successfully executed. The following is the simplest use of Promise
new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('success')/ / the refs
}, 500)
}).then(function (res) {
console.log(res) // success
})
Copy the code
Let’s implement a simple Promise that resolves the Promise. Then principle. The main principle is to nest two callback functions, put the function as parameter in the asynchronous operation, and execute the callback as parameter after the asynchronous operation is executed
function MyPromise(fn) { // The main principle is to use two nested callback functions, put the function as a parameter in the asynchronous operation, when the asynchronous operation is executed as a parameter callback
var _this = this;
_this.params = null; // Parameters to pass
_this.tempResolve = null // _this.tempResolve is used to pass arguments to the then method
function resolve(params) { // The method is executed after an asynchronous operation, waiting until it executes
_this.params = params
_this.tempResolve(_this.params)
}
fn(resolve) // Return resolve via a callback to the asynchronous operation. When resolve executes, the asynchronous operation executes
}
MyPromise.prototype.then = function (_resolve) { // Asynchronous operations pass parameters, which in short join then and resolve
var _this = this
_this.tempResolve = function () {
_resolve(_this.params)
}
}
MyPromise.prototype.constructor = MyPromise
new MyPromise(function (res, rej) {
setTimeout(function () {
res('success')},1000)
})
.then(function (res) {
console.log(res) // success
})
Copy the code
If we understand the above code, we are already half way there. Next, we will further implement the Promise. The difference is that we will add the chain call of then. We added status to each layer of promise to record whether or not the current promise has been executed. TempResolve should also be changed to tempResolveList because more than one function needs to be executed, becoming a queue. We optimized resolve based on the code above
function resolve(params) { // The method is executed after an asynchronous operation, waiting until it executes
if (_this.status === 'pending') {
_this.status = 'resolve'; // After entering the function, modify the function state immediately to prevent the following loop from executing the function repeatedly
_this.params = params;
for (var i = 0; i < array.length; i++) {
_this.tempResolveList[i](_this.params) // The function that executes all chain calls to then}}}Copy the code
In addition, in the THEN function, you need to add a piece of code that returns the Promise to the next level of the chain call and passes the callback to the next level through resolve for sequential synchronized execution
MyPromise.prototype.then = function (tempResolve) { // Asynchronous operations pass parameters, which in short join then and resolve
var _this = this
var _promise = new MyPromise(function (resolve, reject) {
if (_this.status == 'pending') {
_this.tempResolveList.push(function () {
resolve(tempResolve(_this
.params)) // Asynchronously pass the previous tempResolve through the resolve argument to the next Promise, each layer being superimposed asynchronously})}})return _promise // Return Promise for chained calls
}
Copy the code
If we pass tempResolve (resolve), we need to filter resolve. If we pass tempResolve (resolve), we need to filter resolve. If we pass tempResolve (resolve), we need to filter resolve. Then is placed in this layer and executed directly
if (params && typeof params === 'function' || typeof params ===
'object') { // If the parameter is params or MyPromise, the chain call must produce the MyPromise constructor
var _then = params.then // If the argument is the MyPromise constructor, then is placed in this layer to continue with the subsequent operations
if (typeof _then === 'function') {
_then.call(params, resolve); // call then
return; }}Copy the code
Full code for chain calls to promise.then
function MyPromise(fn) { // The main principle is to use two nested callback functions, put the function as a parameter in the asynchronous operation, when the asynchronous operation is executed as a parameter callback
var _this = this;
_this.status = 'pending'; // The async function is executed only when the current Promise is pending
_this.params = null; // Parameters to pass
_this.tempResolveList = new Array(a)// Store the queue of functions in the chained call then
function resolve(params) { // The method is executed after an asynchronous operation, waiting until it executes
if (params && typeof params === 'function' || typeof params ===
'object') { // If the parameter is params or MyPromise, the chain call must produce the MyPromise constructor
var _then = params.then // If the argument is the MyPromise constructor, then is placed in this layer to continue with the subsequent operations
if (typeof _then === 'function') {
_then.call(params, resolve); // call then
return; }}if (_this.status === 'pending') {
_this.status = 'resolve'; // After entering the function, modify the function state immediately to prevent the following loop from executing the function repeatedly
_this.params = params;
for (var i = 0; i < _this.tempResolveList.length; i++) {
_this.tempResolveList[i](_this.params) // The function that executes all chain calls to then
}
}
}
fn(resolve) // Return resolve via a callback to the asynchronous operation. When resolve executes, the asynchronous operation executes
}
MyPromise.prototype.then = function (tempResolve) { // Asynchronous operations pass parameters, which in short join then and resolve
var _this = this
var _promise = new MyPromise(function (resolve, reject) {
if (_this.status == 'pending') {
_this.tempResolveList.push(function () {
resolve(tempResolve(_this
.params)) // In the Promise that passes the previous tempResolve layer to the next layer asynchronously, each layer is superimposed asynchronously})}})return _promise // Return Promise for chained calls
}
MyPromise.prototype.constructor = MyPromise
var count = 1
new MyPromise(function (res, rej) {
setTimeout(function () {
res('success' + count++)
}, 1000)
})
.then(function (res) {
console.log(res) // success1
return new MyPromise(function (res, rej) {
setTimeout(function () {
res('success' + count++)
}, 1000)
})
}).then(function (res) {
console.log(res) // success2
return new MyPromise(function (res, rej) {
setTimeout(function () {
res('success' + count++)
}, 1000)
})
}).then(function (res) {
console.log(res) // success3
})
Copy the code
After implementing the chain call, we implement a simple implementation of reject and catch, which is similar to then. We encapsulate some methods and get the following code (Catch fails to perfect the chain call, resulting in the failure of the then method when the number of executions is greater than 1).
function MyPromise(fn) { // The main principle is to use two nested callback functions, put the function as a parameter in the asynchronous operation, when the asynchronous operation is executed as a parameter callback
var _this = this;
_this.status = 'pending'; // The async function is executed only when the current Promise is pending
_this.params = null; // Parameters to pass
_this.tempResolveList = new Array(a)// Store the queue of functions in the chained call then
_this.tempRejectList = new Array(a)// Store the queue of functions in a chain call to catch
_this.runCommandList = function (_status, _params, _commandList) { // If the function state is pending, the function execution will have two states, resolve and reject
if (_params && typeof _params === 'function' || typeof _params ===
'object') { // If the parameter is params or MyPromise, the chain call must produce the MyPromise constructor
var _then = _params.then // If the argument is the MyPromise constructor, then is placed in this layer to continue with the subsequent operations
if (typeof _then === 'function') {
_then.call(_params, resolve); // call then
return; }}if (_this.status === 'pending') {
_this.status = _status; // After entering the function, modify the function state immediately to prevent the following loop from executing the function repeatedly
_this.params = _params;
for (var i = 0; i < _commandList.length; i++) {
_commandList[i](_this.params) // The function that executes all chain calls to then
}
}
}
_this.runCallBack = function (resolve, reject, finishFn) {
return function () {
try {
var temp = finishFn(_this.params);
resolve(temp);
} catch (error) {
reject(error);
}
}
}
_this.createPromise = function (temp, tempList) {
var _this = this
return new MyPromise(function (resolve, reject) {
if (_this.status == 'pending') {
tempList.push(_this.runCallBack(resolve, reject,
temp)) // In the Promise that passes the previous tempResolve layer to the next layer asynchronously, each layer is superimposed asynchronously}})}function resolve(params) { // The method is executed after an asynchronous operation, waiting until it is returned to the new Promise(fn) argument via a callback
_this.runCommandList('resolve', params, _this.tempResolveList)
}
function reject(params) { // The method is executed after an asynchronous operation, waiting until it is returned to the new Promise(fn) argument via a callback
_this.runCommandList('reject', params, _this.tempRejectList)
}
try { // Catch an exception
fn(resolve, reject)
} catch (error) {
reject(error)
} // Return resolve via a callback to the asynchronous operation. When resolve executes, the asynchronous operation executes
}
MyPromise.prototype.then = function (tempResolve) { // Asynchronous operations pass parameters, which in short join then and resolve
var _this = this
var _promise = _this.createPromise(tempResolve, _this.tempResolveList)
_promise.catch = function (tempReject) { // Asynchronous operations pass parameters, which in short join then and resolve
_this.createPromise(tempReject, _this.tempRejectList)
}
return _promise // Return Promise for chained calls
}
MyPromise.prototype.constructor = MyPromise
var count = 1
new MyPromise(function (res, rej) {
setTimeout(function () {
rej('success' + count++)
}, 1000)
// setTimeout(function () {
// res('success' + count++)
// }, 1000)
})
.then(function (res) {
console.log(res) // success1
return new MyPromise(function (res, rej) {
setTimeout(function () {
res('success' + count++)
}, 1000)
})
}).catch(function (err) {
console.log(err) // success1
})
Copy the code
Summary: the code may have some imperfections, welcome to point out