Hand written promise

osc A 3gbrdm 2020-11-10 12:53:27
hand written promise


Learning materials : Largo class 《 Big front end high salary training camp 》
Reading suggestions : The article is longer , Eat with the sidebar table of the article , Experience will be better !

Promise Object is one that can manage synchronization / The state and data container of the results of an asynchronous operation . its Core logic It is the external operation to reasonably put its running result status and data Let the container store and manage , And then from the outside Take out of container The state and data of the external operation are used for the next operation .

The next part of this article is handwritten from the following Promise The five key understandings of the study began to explore , And finally finish handwriting Promise:

  • Promise The basic shape of the container ( Properties and behavior of containers )
  • Promise How the container is constructed ( Container hosting excutor Function run result status and data )
  • Go to Promise Write data into the container (resolve、reject The function is responsible for )
  • from Promise Read data from the container (then Method is responsible for )
  • Realization then Chain call of function

One :Promise The basic shape of the container ( Properties and behavior of containers )

1. Container managed data ( attribute )

  • state state:pending、resolved / fulfilled、rejected
  • result value: Containers resolved / fulfilled State data
  • Refusals reason: Containers rejected State data
  • onResolvedTodoList:pending Add... To the status , Containers resolved / fulfilled An array of callback behaviors after state
  • onRejectedTodoList:pending Add... To the status , Containers rejected An array of callback behaviors after state

2. Read and write container data ( Behavior )

  • Write operations : The container defines a set of internal state and data resolve and reject Method , To write data to the container from outside (value / reason). actually ,Promise The container has constraints on write operations , It only allows initialization of write operations , Write changes are not allowed .
  • Read operations : The container defines an internal state that can read internal state and data then Method , To trigger the corresponding callback behavior after external reading the state and data in the container .

3. Code implementation

class Container {

state = undefined;
value = undefined;
reason = undefined;
constructor(excutor) {
 // Construct container }
resolve = value => {
 // Write container data }
reject = reason => {
 // Write container data }
onResolvedTodoList = [];
onRejectedTodoList = [];
then(onResolved, onRejected) {
 // Reading container data }
}
Container.PENDING = 'pending';
Container.RESOLVED = 'resolved';
Container.REJECTED = 'rejected';

Two :Promise How container instances are constructed ( Container hosting excutor Function run result status and data )

1. Construct the parameter function of the method excutor The definition of

  • Where to define : Container external definition
  • Functional responsibilities :1 yes Business operation carrier .2 yes hold excutor After running the state and data to the container management .

An example of calling constructor outside the container :

// Focus on : Construction parameters excutor Definition of function , It defines two formal parameters resolve and reject
const p1 = new Container((resolve, reject) => {

// The internal logic determines when to initialize the container data , What data to initialize 
setTimeout(() => {

resolve(0)
})
})

2. Construct the parameter function of the method excutor Call to

  • Where to call : Call inside the container
  • Timing of invocation : Call when the container instance is constructed

The implementation example of the constructor inside the container :

class Container {

state = undefined;
value = undefined;
reason = undefined;
// Focus on : Construction parameters excutor Function call , When it is called and the arguments are passed .
constructor(excutor) {

try {

excutor(this.resolve, this.reject);
this.state = Container.PENDING;
} catch (e) {

this.reject(e)
}
}
resolve = value => {
 // Write container data }
reject = reason => {
 // Write container data }
then(onResolved, onRejected) {
 // Reading container data }
}
Container.PENDING = 'pending';
Container.RESOLVED = 'resolved';
Container.REJECTED = 'rejected';

3、 ... and : Go to Promise Write data into the container (resolve、reject The function is responsible for )

1.resolve、reject Definition of function

  • Where to define : The internal definition of the container is
  • Functional responsibilities : hold excutor After running the state and data to the container management .
  • Update of container state and data is not allowed : If the container state is not pending Shall be regarded as invalid notice , Do nothing .
  • Callback array to handle state subscription :onResolvedTodoList and onRejectedTodoList The array stores the callback function that subscribes to a certain state , After initializing the container managed state and data , According to the state of the container , The callback functions are taken from the callback array one by one according to the insertion order .
  • Defined inside the container : Defined inside the container , Easy to access and set container state and data .
  • Defined as arrow function : Defined as arrow function , The caller cannot change its internal this Point to , Even using call、apply、bind function .

The inside of the container is to resolve and reject Implementation example of :

class Container {

constructor(excutor) {
}
resolve = value => {

if (this.state != Container.PENDING) return
this.status = Container.RESOLVED;
this.value = value;
while (this.onResolvedTodoList.length) this.onResolvedTodoList.shift()() // Take out the first one 
}
reject = reason => {

if (this.state != Container.PENDING) return
this.status = Container.REJECTED;
this.reason = reason;
while (this.onRejectedTodoList.length) this.onRejectedTodoList.shift()()
}
then(onResolved, onRejected) {
}
}

2.resolve、reject Function call

  • Where to call : Call outside the container
  • Timing of invocation : Support synchronization 、 Call asynchronously , When called asynchronously , It is represented by the call of callback function .

On the outside of the container resolve and reject Call example of :

const p1 = new Promise((resolve, reject) => {

// Write data to the container synchronously 
// resolve(0)
// Write data to the container asynchronously 
setTimeout(() => {

resolve(1)
})
})

Four : from Promise Read data from the container (then Method is responsible for )

1.then Definition of function

  • Where to define : The internal definition of the container is
  • Functional responsibilities : Receive two callback functions from the caller , Determine which function to execute according to the state stored in the container , At the same time, the data stored in the container is used as input to execute this function .
  • Optional state handling function : Allow callers to operate on only one state .
  • pending State processing :pending In the state of , The container didn't get excutor Status and data of running results , So put the two callback functions into the callback function array onResolvedTodoList and onRejectedTodoList in , Wait for the program to run and get excutor Execute the status and data of the result and deliver it to container management before executing , That's the container resolve and reject After method call .

The inside of the container is to then Function implementation example :

class Container {

constructor(excutor) {
}
resolve = value => {
}
reject = reason => {
}
onResolvedTodoList = [];
onRejectedTodoList = [];
then(onResolved, onRejected) {

onResolved = onResolved ? onResolved : value => value;
onRejected = onRejected ? onRejected : reason => {
 throw reason };
switch (this.state) {

case Container.PENDING:
this.onResolvedTodoList.push(() => {

try {

const value = onResolved(this.value);
resolve(value);
} catch (e) {

reject(e);
}
});
this.onRejectedTodoList.push(() => {

try {

const value = onRejected(this.reason);
reject(value);
} catch (e) {

reject(e);
}
});
break;
case Container.RESOLVED:
try {

const value = onResolved(this.value);
resolve(value);
} catch (e) {

reject(e);
}
break;
case Container.REJECTED:
try {

const value = onRejected(this.reason);
resolve(value);
} catch (e) {

reject(e);
}
break;
}
}
}

2.then Function call

  • Where to call : Call outside the container
  • Timing of invocation : After the container instance is constructed . Be careful : After the container instance is constructed , Before writing state and data asynchronously to the container Within the time difference , The state and data in the container are not ready yet .

On the outside of the container then Function call example :

p1.then((value) => {

console.log(value)
}, (reason) => {

console.log(reason)
})

5、 ... and : Realization then Chain call of function

  • then Function does not support chained calls :then Function has no return value , It can be called many times , But it can only do one step based on the container state and data , Unable to implement pipelining of operations , such Still can't solve callback function loop nesting The problem of .
  • then Function support chain call advantages :then function Construct and return a new container according to the execution result of callback function , In this way, the outside can deal with then The function call returns the container state and data, and then do the next operation . So again and again , Can be realized The pipelining of operations and Solve the nesting problem of callback functions .

1.then The definition of function is enhanced

then Method returns a container object , The state and data managed by the new container object are determined by the execution result of the callback function .
  • If the callback function runs, it returns a value , Call resolve Method to initialize the state and data of the new container .
  • If the callback function returns a container and is not the new container itself , I'm going to call this The container returned by the callback function then Method to read Its internal management status and data , Then Call the new container's resolve perhaps reject Method to initialize a new container State and data of . The specific communication process of reading first and then writing , By putting New container of resolve perhaps reject Method returns the next operation of the container as a callback function ( That is to say, to act separately as then Method parameters onResolved and onRejected) To achieve .
  • If the callback function runs, it returns the new container itself , If no special treatment , The state and data of the new container will be read as the state and data of the new container , It will never end , Into an infinite cycle . The solution to this problem , Is to let the callback function run ( New container of excutor) Put in the task queue as an asynchronous task , The benefits of doing this Before initializing the state and data of this new container , You can get the new container object to judge .

The inside of the container is to then Function support chain call implementation example :

class Container {

constructor(excutor) {
}
resolve = value => {
}
reject = reason => {
}
onResolvedTodoList = [];
onRejectedTodoList = [];
then(onResolved, onRejected) {

onResolved = onResolved ? onResolved : value => value;
onRejected = onRejected ? onRejected : reason => {
 throw reason };
let containerBack = new Container((resolve, reject) => {

switch (this.state) {

case Container.PENDING:
this.onResolvedTodoList.push(() => {

setTimeout(() => {

try {

const value = onResolved(this.value);
resolveContainer(containerBack, value, resolve, reject);
} catch (e) {

reject(e);
}
})
});
this.onRejectedTodoList.push(() => {

setTimeout(function () {

try {

const value = onRejected(this.reason);
resolveContainer(containerBack, value, resolve, reject);
} catch (e) {

reject(e);
}
})
});
break;
case Container.RESOLVED:
setTimeout(() => {

try {

const value = onResolved(this.value);
resolveContainer(containerBack, value, resolve, reject);
} catch (e) {

reject(e);
}
})
break;
case Container.REJECTED:
setTimeout(function () {

try {

const value = onRejected(this.reason);
resolveContainer(containerBack, value, resolve, reject);
} catch (e) {

reject(e);
}
})
break;
}
});
return containerBack
}
}
function resolveContainer(containerBack, value, resolve, reject) {

if (!(value instanceof Container)) {

resolve(value)
} else {

if (value === containerBack) {

reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
} else {

value.then(resolve, reject);
}
}
}

2.then Chain call of function

  • then The purpose of the chain call is : Calling then After method , The caller can do the next operation according to the execution result of the callback function , That is to say The callback function that listens to the result of the callback function .

On the outside of the container then Examples of chained calls to functions :

const p2 = p1.then((value) => {

console.log(value)
}, (reason) => {

console.log(reason)
})
p2.then((value) => {

console.log('p2', value)
}, (reason) => {

console.log('p2', reason)
}).then((value) => {

console.log('p3', value)
}, (reason) => {

console.log('p3', reason)
})

In this paper, the end , Thank you for watching .
If you approve , One key, three links .

版权声明
本文为[osc A 3gbrdm]所创,转载请带上原文链接,感谢

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple