Principle and implementation of promise

Sauted spareribs 2021-05-03 20:52:19
principle implementation promise


We are used to using Promise 了 , But how does it work ? Let's analyze .
According to teacher Ruan Yifeng 《ES6 introduction 》 For in the Promise Explanation . We can find out ,Promise There are two characteristics :
image.png
According to what we use Promise The situation of , As well as the characteristics, we summarize the following points :
1、Promise It's an asynchronous operation .
2、Promise There are three states (pending、fulfilled、rejected), For the initial pending, The other two are result states .
3、 If the state has changed , Then again then It will return the result immediately when it is finished .
4、Promise The constructor takes a function , Function has resolve、reject Parameters .
5、Promise adopt then You can add multiple callback functions , When the state changes , Will trigger the execution of these callbacks in the corresponding state .
6、then There are two parameters , A callback for success 、 A failed callback , The value of the resulting state goes into the callback .
7、promise Meeting catch Live inside the abnormal situation .
Through the above summary , We can initially achieve a Promise The skeleton of the .

const STATUS = Object.freeze({ // Define three states 
PENDING: "pending",
FULFILLED: "fulfilled",
REJECTED: "rejected"
})
class MyPromise {
_status = STATUS.PENDING; // The initial state 
_value = undefined; // Execution results 
_fulfilledFun = []; // fulfilled The status corresponds to the task queue to be executed 
_rejectedFun = [] // rejected The status corresponds to the task queue to be executed 
constructor(handle) {
if (!this._isFunction(handle)) {
throw TypeError('arguments must be a function')
}
try { // promise Meeting catch Live inside the execution exception 
handle(this._resolve.bind(this), this._reject.bind(this)) // Promise The callback of the constructor has two parameters 
} catch (err) {
this._reject(err)
}
}
_isFunction(handle) {
return typeof handle === 'function'
}
_run(tasks) {
let cb;
while (cb = tasks.shift()) {
cb()
}
}
_resolve(val) {
if (this._status !== STATUS.PENDING) return;
this._status = STATUS.FULFILLED;
this._value = val;
setTimeout(() => { /// To simulate asynchrony , Implementation follow promise The same asynchronous effect , But here is the macro queue , Not really promise Micro queue 
this._run(this._fulfilledFun)
}, 0)
}
_reject(val) {
if (this._status !== STATUS.PENDING) return;
this._status = STATUS.REJECTED;
this._value = val;
setTimeout(() => {
this._run(this._rejectedFun)
}, 0)
}
then(resolve, reject) {
const { _status, _value } = this;
switch (_status) {
// Add multiple callbacks to the corresponding state task queue 
case STATUS.PENDING:
this._fulfilledFun.push(resolve)
this._rejectedFun.push(reject)
break;
// If the state changes, the result is returned immediately 
case STATUS.FULFILLED:
resolve(_value)
break;
case STATUS.REJECTED:
reject(_value)
break;
}
}
}
var p = new MyPromise((res, rej) => {
res(3333)
})
p.then((res) => {
console.log(1, res)
})
console.log(1)
// Execution results 
//1
//1 3333
 Copy code 

Above we have achieved a basic Promise skeleton .
image.png
As shown in the picture, we can find that ,then Back to a Promise example , But we didn't go back , So we're going to take then modified , Yes then Make an extension .

class MyPromise {
//.....
// Used to deal with then The return value of 
_handleCheck(preTask, nextTask, nextResolve, nextReject) {
let result = this._value;
try {
if (this._isFunction(preTask)) {
result = preTask(result)
if (result instanceof MyPromise) { // If then Back to a promise Words , So the next chained call uses then in promise The return value of 
result.then(nextResolve, nextReject)
} else {
nextTask(result)
}
} else { // This needs attention , If then If it's not a function , that then The next chained call of is then Received value 
nextTask(result)
}
} catch (err) {
nextReject(err)
}
}
then(resolve, reject) {
const { _status } = this;
return new MyPromise((nextResolve, nextReject) => {
// Preprocess the queue , Mainly then The result is that , In order to ensure the correct transfer of parameters to the next level of chain call 
const _fulfilledHandle = this._handleCheck.bind(this, resolve, nextResolve, nextResolve, nextReject)
const _rejectedHandle = this._handleCheck.bind(this, reject, nextReject, nextResolve, nextReject)
switch (_status) {
case STATUS.PENDING:
this._fulfilledFun.push(_fulfilledHandle)
this._rejectedFun.push(_rejectedHandle)
break;
case STATUS.FULFILLED:
_fulfilledHandle()
break;
case STATUS.REJECTED:
_rejectedHandle()
break;
}
})
}
}
var p = new MyPromise((res, rej) => {
res(3333)
})
p.then((res) => {
console.log(1, res)
return 67
}).then((res) => {
console.log(5, res)
})
/**
* Return results
1
1 3333
5 67
*/
 Copy code 

Such a basic core function has been realized .Promise There are other ways , We can realize one by one through these basic functions .

1、catch

image.png

catch(reject) {
return this.then(undefined, reject)
}
 Copy code 

2、finally

image.png
image.png

finally(callback) {
return this.then(
value => MyPromise.resolve(callback()).then(() => value),
error => MyPromise.resolve(callback()).then(() => {throw error})
)
}
 Copy code 

3、all

image.png

static all(list) {
return new MyPromise((res, rej) => {
const values = [];
const size = list.length;
for(let [index, p] of list.entries() ){
MyPromise.resolve(p).then(v => {
values[index] = v;
if(index === size - 1) res(values)
}).catch(err => rej(err))
}
})
}
 Copy code 

4、race

image.png

static race(list) {
return new MyPromise((res, rej) => {
for(let p of list) {
// Use MyPromise.resolve Not directly p.then To prevent p It's not a normal promise
MyPromise.resolve(p).then(result => {
res(result)
}, error => rej(error))
}
})
}
 Copy code 

5、allSettled

image.png

static allSettled(list) {
const values = [];
const size = list.length;
let count = 0;
return new MyPromise((res, rej) => {
const getValues = (val, index) => {
values[index] = val;
count++;
if(count === size) res(values)
}
for(let [index, p] of list.entries()) {
MyPromise.resolve(p).then(result => {
getValues(result, index)
}, error => getValues(error, index))
}
})
}
 Copy code 

6、any

image.png

static any(list) {
const values = [];
const size = list.length;
return new MyPromise((res, rej) => {
for(let [index, p] of list.entries()) {
MyPromise.resolve(p).then(result => {
res(result)
}, error => {
values[index] = error;
if(index === size - 1) rej(values)
})
}
})
}
 Copy code 


Here is the complete code implementation .

const STATUS = Object.freeze({
PENDING: "pending",
FULFILLED: "fulfilled",
REJECTED: "rejected"
})
class MyPromise {
_status = STATUS.PENDING;
_value = undefined;
_fulfilledFun = [];
_rejectedFun = []
constructor(handle) {
if (!this._isFunction(handle)) {
throw TypeError('arguments must be a function')
}
try {
handle(this._resolve.bind(this), this._reject.bind(this))
} catch (err) {
this._reject(err)
}
}
_isFunction(handle) {
return typeof handle === 'function'
}
_run(tasks) {
let cb;
while (cb = tasks.shift()) {
cb()
}
}
_resolve(val) {
if (this._status !== STATUS.PENDING) return;
this._status = STATUS.FULFILLED;
this._value = val;
setTimeout(() => { /// To simulate asynchrony , Implementation follow promise The same asynchronous effect , But here is the macro queue , Not really promise Micro queue 
this._run(this._fulfilledFun)
}, 0)
}
_reject(val) {
if (this._status !== STATUS.PENDING) return;
this._status = STATUS.REJECTED;
this._value = val;
setTimeout(() => {
this._run(this._rejectedFun)
}, 0)
}
_handleCheck(preTask, nextTask, nextResolve, nextReject) {
let result = this._value;
try {
if (this._isFunction(preTask)) {
result = preTask(result)
if (result instanceof MyPromise) {
result.then(nextResolve, nextReject)
} else {
nextTask(result)
}
} else {
nextTask(result)
}
} catch (err) {
nextReject(err)
}
}
then(resolve, reject) {
const { _status } = this;
return new MyPromise((nextResolve, nextReject) => {
const _fulfilledHandle = this._handleCheck.bind(this, resolve, nextResolve, nextResolve, nextReject)
const _rejectedHandle = this._handleCheck.bind(this, reject, nextReject, nextResolve, nextReject)
switch (_status) {
case STATUS.PENDING:
this._fulfilledFun.push(_fulfilledHandle)
this._rejectedFun.push(_rejectedHandle)
break;
case STATUS.FULFILLED:
_fulfilledHandle()
break;
case STATUS.REJECTED:
_rejectedHandle()
break;
}
})
}
catch(reject) {
return this.then(undefined, reject)
}
finally(callback) {
return this.then(
value => MyPromise.resolve(callback()).then(() => value),
error => MyPromise.resolve(callback()).then(() => {throw error})
)
}
static resolve(value) {
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value))
}
static reject(value) {
if (value instanceof MyPromise) return value;
return new MyPromise((resolve, reject) => reject(value))
}
static all(list) {
return new MyPromise((res, rej) => {
const values = [];
const size = list.length;
for(let [index, p] of list.entries() ){
MyPromise.resolve(p).then(v => {
values[index] = v;
if(index === size - 1) res(values)
}).catch(err => rej(err))
}
})
}
static race(list) {
return new MyPromise((res, rej) => {
for(let p of list) {
// Use MyPromise.resolve Not directly p.then To prevent p It's not a normal promise
MyPromise.resolve(p).then(result => {
res(result)
}, error => rej(error))
}
})
}
static allSettled(list) {
const values = [];
const size = list.length;
let count = 0;
return new MyPromise((res, rej) => {
const getValues = (val, index) => {
values[index] = val;
count++;
if(count === size) res(values)
}
for(let [index, p] of list.entries()) {
MyPromise.resolve(p).then(result => {
getValues(result, index)
}, error => getValues(error, index))
}
})
}
static any(list) {
const values = [];
const size = list.length;
return new MyPromise((res, rej) => {
for(let [index, p] of list.entries()) {
MyPromise.resolve(p).then(result => {
res(result)
}, error => {
values[index] = error;
if(index === size - 1) rej(values)
})
}
})
}
}
 Copy code 
版权声明
本文为[Sauted spareribs]所创,转载请带上原文链接,感谢
https://qdmana.com/2021/05/20210503204933705y.html

  1. Analysis of MVC
  2. [middle stage] please stay and join me in the backstage
  3. Understanding front end garbage collection
  4. [continuous update] front end special style implementation
  5. Flutter product analysis and package reduction scheme
  6. XPath positioning
  7. 前端开发css中的flex布局的使用
  8. The use of flex layout in front end development CSS
  9. JQuery核心函数和静态方法
  10. JQuery core functions and static methods
  11. Node family - understanding of blocking and non blocking
  12. 热点微前端Microfrontend的讨论:谷歌AdWords是真实的微前端
  13. Vue source code analysis (2) initproxy initialization proxy
  14. What's TM called react diff
  15. Summary of common front end data structure
  16. Useeffect in hooks
  17. [encapsulation 02 design pattern] Command pattern, share meta pattern, combination pattern, proxy pattern, strategy pattern
  18. Front end notes: virtual Dom and diff of vue2. X
  19. The best code scanning plug-in of flutter
  20. The simplest plug-in for rights management of flutter
  21. 21. Object oriented foundation "problems and solutions of object traversal"
  22. Discussion on hot micro front end: Google AdWords is a real micro front end
  23. Usecallback and usememo for real performance optimization
  24. 【前端圭臬】十一:从规范看 JavaScript 执行上下文(下)
  25. [front end standard] 11: Javascript execution context from the perspective of specification (2)
  26. Hexagonal六角形架构ReactJS的实现方式 - Janos Pasztor
  27. Transaction of spring's reactive / imperative relational database
  28. The implementation of hexagonal hexagonal reactjs Janos pasztor
  29. HTTP状态码:402 Payment Required需要付款 - mozilla
  30. HTTP status code: 402 payment required - Mozilla
  31. Factory mode, constructor mode and prototype mode
  32. Build the scaffold of react project from scratch (Series 1: encapsulating a request method with cache function based on Axios)
  33. Cocos Quick Start Guide
  34. Comparison of three default configurations of webpack5 modes
  35. A case study of the combination of flutter WebView and Vue
  36. CSS: BFC and IFC
  37. A common error report and solution in Vue combat
  38. JS: this point
  39. JS: prototype chain
  40. JavaScript series -- promise, generator, async and await
  41. JS: event flow
  42. Front end performance optimization: rearrangement and redrawing
  43. JS - deep and shallow copy
  44. JavaScript异步编程3——Promise的链式使用
  45. JavaScript asynchronous programming 3 -- chain use of promise
  46. Vue.js组件的使用
  47. The use of vue.js component
  48. How to judge whether a linked list has links
  49. Element UI custom theme configuration
  50. Text image parallax effect HTML + CSS + JS
  51. Spring的nohttp宣言:消灭http://
  52. Vue3 intermediate guide - composition API
  53. Analysis of URL
  54. These 10 widgets that every developer must know
  55. Spring's nohttp Manifesto: eliminate http://
  56. Learn more about JS prototypes
  57. Refer to await to JS to write an await error handling
  58. A short article will directly let you understand what the event loop mechanism is
  59. Vue3 uses mitt for component communication
  60. Characteristics and thinking of ES6 symbol