Why implement promises?? Because the previous schemes were not good enough, some did not conform to the description of MDN, some did not conform to the Promise /A+ specification, and some were not compatible with the use of synchronous and asynchronous internal functions. So do it yourself and implement PromiseDemo. Here are the test cases and source code.

The following test cases have been passed:

Use case 1: resolve in synchronization

New PromiseDemo(function(resolve, reject){resolve(' sync ')}).then(function(res) {console.log(res); / / synchronize});Copy the code

// Use case 2:resolve is promise

new PromiseDemo(function(resolve, reject){

  resolve(new PromiseDemo(function(reso) {reso('resolve-promose')}))

}).then(function(res) {

  console.log(res); // resolve-promose

}); 
Copy the code

// Use case 3: error capture

New PromiseDemo(function(resolve, reject){throw new Error(' Error '); resolve(123) }).then(function(res) { console.log(res); }).catch(function(err) { console.log(err); }); // at <anonymous>:2:9 // at new PromiseDemo (<anonymous>:9:13) // at <anonymous>:1:1Copy the code

Use case 4: Async resolve

new PromiseDemo(function(resolve, rej) {

  setTimeout(function() {

​    resolve(1);

  }, 10)

}).then(function(res) {

  console.log(res); // 1

}, function(err) {

  console.log(err);

});  
Copy the code

Use case 5:all method

PromiseDemo. All ([the fetch (' https://cdn.bootcss.com/vue/2.5.16/vue.min.js' {method: 'GET'}). Then ((r) = > r.t ext ()), then ((r) = > r.s lice (6, 19). fetch('https://unpkg.com/react@16/umd/react.production.min.js', {method: 'GET'}). Then ((r) = > r.t ext ()), then ((r) = > r.s lice (13, 27)),]). Then (function (res) {the console. The log (res); // [" Vue. Js v2.5.16", "React v16.14.0"]});Copy the code

Use case 6: The RACE method requests different resources

PromiseDemo. Race ([the fetch (' https://cdn.bootcss.com/vue/2.5.16/vue.min.js' {method: 'GET'}). Then ((r) = > r.t ext ()), then ((r) = > r.s lice (6, 25)), fetch (' https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js', {method: 'GET'}). Then ((t) = > t.t ext ()), then ((r) = > r.s lice (3) in 2)]), then (function (res) {the console. The log (res); / / the Vue. Js v2.5.16});Copy the code

Use case 7: The RACE method requests different resources

PromiseDemo.race([ fetch('https://unpkg.com/react@16/umd/react.production.min.js', {method: 'GET'}). Then ((r) = > r.t ext ()), then ((r) = > r.s lice (13, 27)), fetch (' https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js', {method: 'GET'}). Then ((t) = > t.t ext ()), then ((r) = > r.s lice (3) in 2)]), then (function (res) {the console. The log (res); / / jQuery v3.4.1});Copy the code

PromiseDemo implementation source code

For those who are interested, it is suggested to view the code sequence:

1.constructor

2.resolve

3.then

4.reject

5.catch

6.finally

7.all

8.race

Resolve, reject, all, and race are static methods according to MDN

According to the Promise/A+ specification, the parameter of Resolve may be A Promise. Therefore, resolve needs to be determined if it is an instance of PromiseDemo and then split logically.

Class PromiseDemo {/** constructor * initialize then event queue, catch event queue, status * execute parameter fn, Pass resolve and reject */ constructor(fn) {if (fn &&typeof fn! == 'function') throw new Error(`Parameter is not a function`); this.thenQue = [] this.catchQue = [] this.status = '<pending>'; try { fn && fn(PromiseDemo.resolve.bind(this), PromiseDemo.reject.bind(this)); } catch(e) { PromiseDemo.reject.bind(this)(e); This function will be fulfilled only if the state is fulfilled. This function will be fulfilled only if the parameter of resolve is not a PromiseDemo instance. If resolve is a PromiseDemo instance, then expose the internal resolve value or the return value of the then function, and connect the external RESOLVE execution to the external THEN queue, which can then be executed in sequence. Promise.resolve(). Then () * setTimeout is used in the promise.resolve () function to add subsequent logic to the next macro task. Promise is a microtask. SetTimeout is used to implement the promise effect, because there are no asynchronous functions except mutation and promise in the browser environment. */ static resolve(data) { if (this.status === '<fulfilled>') return; this.value = data; const isInstance = data instanceof PromiseDemo; if (! isInstance) { setTimeout(() => { try { this.thenQue.forEach((item) => { this.value = item(this.value); }); this.thenQue = []; this.status = '<fulfilled>'; } catch (e) { this.status = '<rejected>'; PromiseDemo.reject.bind(this)(e); }}); } else { data.then((res) => { PromiseDemo.resolve.bind(this)(res); }).catch((err) => { PromiseDemo.reject.bind(this)(err); }); } if (! data) { return new PromiseDemo(); }} static reject(err) {if (this.status === 'reject >') return;}} static reject(err) {if (this.status ===' reject >') return; this.error = err; let count; setTimeout(() => { try { this.catchQue.forEach((item, index) => { count = index; this.error = item(this.error); }); this.catchQue = []; this.status = '<rejected>'; } catch (e) { this.catchQue = this.catchQue.slice(count+1); PromiseDemo.reject.bind(this)(e); }}); if (! err) { return new PromiseDemo(); }} /** then function * is used to collect all the functions in the then function. ThenQue */ THEN (onResolve, onReject) {if (typeof onReject === 'function') {this.catchque.push (onReject); } typeof onResolve === 'function' && this.thenQue.push(onResolve); return this; CatchQue */ catch(fn) {this.catchque.push (fn); return this; } / finally(thenQue) {this.thenque.push (fn);} / finally(thenQue) {this.thenque.push (fn); this.catchQue.push(fn); } /** Add then methods to each of the then internal methods to determine whether all promises have been executed. If all promises have been executed, Resolve */ static all(arr) {const resArr = []; const length = arr.length; let resCount = 0; let that; try { arr.forEach(function(item, index) { item.then(function(res) { resArr[index] = res; resCount++; if (resCount === length) { PromiseDemo.resolve.bind(that)(resArr); }})}); } catch (e) { PromiseDemo.reject.bind(that)(e); } that = new PromiseDemo(); return that; } static race(arr) {let that; static race(arr) {let that; try { arr.forEach(function(item, index) { item.then(function(res) { PromiseDemo.resolve.bind(that)(res); })}); } catch (e) { PromiseDemo.reject.bind(that)(e); } that = new PromiseDemo(); return that; }}Copy the code