This time, a thorough understanding of the source code ideology Promise

About Promise source implementation, there are too many answers online, I also read a lot of information, but not very clear. Until one day I finish school functor of functional programming concepts, Promise fishes have a more profound understanding of the source code. Today, let us re-learn what Promise.

We know that the birth of Promise is to solve the problem "callback hell", it is synchronized with the chain way to solve the asynchronous nested callbacks.

What? Synchronization chain? Is not that what we thought functor on a study of it? If you understand the functor, then come to learn Promise source code easier to understand. Next, we explore what functor and Promise has a kind of relationship.

Promise to implement a simple functor

First recall functor Functor chain call:

class Functor{
       constructor (value) {
          this.value = value ;
       }      
       map (fn) {
         return Functor.of(fn(this.value))
       }
    }

Functor.of = function (val) {
     return new Functor(val);
}

Functor.of(100).map(add1).map(add1).map(minus10)

// var  a = Functor.of(100);
// var  b = a.map(add1);
// var  c = b.map(add1);
// var  d = c.map(minus10);

Functor chained calls
The core functor is this: every functor Functor is a new object with the map function on the prototype chain of the object. Passed in by the function fn go to the map stored in the processing data functor, with the value obtained to generate a new sub-function.

Etc ... functor is synchronized chain, and Promise is asynchronous chain. That value is above a asynchronously, then how about we pass this.value value it?

function executor(resolve){
  setTimeout(()=>{ resolve(100) },500)
}

We look after the simulation by setTimeout500 100 milliseconds to get data. In fact, very simple, we can pass in a callback function resolve to deal with this data.

class Functor {
   constructor (executor) {
      let self = this;
      this.value = undefined;

      // 回调函数,用来赋值给 value
      function resolve(value){
          self.value = value;
      }
      executor(resolve)
   } 
}

var a = new Functor(executor);

Explain the above code: we will executor incoming and executed immediately resolve the callback function we can get the value value, we define the callback function will resolve the value of the value assigned this.value.

So we relaxed a complete assignment of the object. Because it is asynchronous to get, then we how to handle the data it used method?

According to the idea functor, after collecting data, we should let the map in the fn function to handle the incoming data. Because it is asynchronous processing, resolve to get the data after the execution, so we define a callback function, the callback fn executed inside. Finally, the results of the processing to the next fn functor resolve to save.

class Functor {
   constructor (executor) {
      let self = this;
      this.value = undefined;
      this.callback = null;
      // 回调函数,用来赋值给 value
      function resolve(value){
           self.value = value
           self.callback()  // 得到 value 之后,在 callback 里面执行 map 传入的 fn 函数处理数据
      }
      executor(resolve)
   } 
  
   map (fn) {
       let  self = this;
       return new Functor((resolve) => {
          self.callback = function(){
              let data =  fn(self.value)   
              resolve(data)
           }
       })
   }    
}

new Functor(executor).map(add1).map(add1)

At the same time call the same functor Promise

Promise addition to chain calls, but also at the same time calls, such as:

var a = new Functor(executor);
var b = a.map(add);
var c = a.map(minus);

Like the above at the same time calling a functor. You will find that it is actually implemented only c. The reason is simple, b give a callback of the assignment, then a c gave the callback assignment. So the b to overwrite the matter will not be executed. To solve this problem is very simple, we just let callback into an array solved.

class Functor {
   constructor (executor) {
      let self = this;
      this.value = undefined;
      this.callbacks = [];
      function resolve(value){
          self.value = value;
          self.callbacks.forEach(item => item())
      }
      executor(resolve)
   } 
  
   then (fn) {
       return new MyPromise((resolve) => {
          this.callbacks.push (()=>{
              let data =  fn(this.value) 
              console.log(data)         
              resolve(data)
           })
       })
   }    
}

var a = new MyPromise(executor);
var b = a.then(add).then(minus);
var c = a.then(minus);

We define callbacks array, then the method each time a call. Callbacks will save it to the array.
When the callback function to get the value of resolve traversed in the execution of each function.
If callbacks are empty, forEach will not be executed, which also solves the wrong problem before
then we further changed the name functor is MyPromise, the map changed then
simplify the return of, let self = this;

Increase reject the callback function

We all know that when the asynchronous call, we often can not get the data, return an error message. This section, we process the error.

class MyPromise {
  constructor (executor) {
    let self = this;
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    function resolve(value){
      self.value = value;
      self.onResolvedCallbacks.forEach(item => item())
    }
    function reject(reason){
      self.reason = reason;
      self.onRejectedCallbacks.forEach(item => item());
    }
    executor(resolve, reject);
  } 
  then (fn,fn2) {
    return new MyPromise((resolve,reject) => {
      this.onResolvedCallbacks.push (()=>{
        let data =  fn(this.value) 
        console.log(data)         
        resolve(data)
      })
      this.onRejectedCallbacks.push (()=>{
        let reason =  fn2(this.reason) 
        console.log(reason)         
        reject(reason)
      })
    })
  }    
}

In fact, very simple, that we would be passing into a multi-executor reject
the results of the asynchronous execution to determine execute resolve, or reject
and then we define and resolve to reject the same method as in MyPromise
then when we then should pass in two parameters, fn, fn2

This time will be a function executor function package asyncReadFile asynchronous read the file

function asyncReadFile(url){
  return new MyPromise((resolve,reject) => {
    fs.readFile(url, (err, data) => {
      if(err){ 
         console.log(err)
         reject(err)
      }else {
         resolve(data)
      }
    })
  })
}
var a = asyncReadFile('./data.txt');
a.then(add,mismanage).then(minus,mismanage);

This is the process we usually packaged Promise asynchronous function, a process in which there did not feel seen. Look carefully, currying asyncReadFile not that we mentioned earlier.

Promise increase state

We define the state of progress is pending
after successfully executed is fulfilled
fail to rejected

class MyPromise {
  constructor (executor) {
    let self = this;
    this.status = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    function resolve(value){
      if (self.status === 'pending') {
        self.status = 'fulfilled';
        self.value = value;
        self.onResolvedCallbacks.forEach(item => item())
      }
    }
    function reject(reason){
      if (self.status === 'pending') {
        self.status = 'rejected';  
        self.reason = reason;
        self.onRejectedCallbacks.forEach(item => item());
      }
    }
    executor(resolve, reject);
  } 
  then (fn,fn2) {
     return new MyPromise((resolve,reject) => {
      if(this.status === 'pending'){
        this.onResolvedCallbacks.push (()=>{
          let data =  fn(this.value) 
          console.log(data)         
          resolve(data)
        })
        this.onRejectedCallbacks.push (()=>{
          let reason =  fn2(this.reason) 
          console.log(reason)         
          reject(reason)
        })
      }
      if(this.status === 'fulfilled'){
          let x = fn(this.value)
          resolve(x)
      }
      if(this.status === 'rejected'){
          let x = fn2(this.value)
          reject(x)
      }
    })
  }    
}

var a = asyncReadFile('./data.txt');
a.then(add,mismanage).then(add,mismanage).then(add,mismanage);

Finally, for now pass in method fn (this.value), we need to spend a sermon Maybe functor to filter it.

Maybe functor optimization

 then (onResolved,onRejected) {
     
     onResolved = typeof onResolved === 'function' ? onResolved : function(value) {}
     onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {}

     return new MyPromise((resolve,reject) => {
      if(this.status === 'pending'){
        this.onResolvedCallbacks.push (()=>{
          let x =  onResolved(this.value) 
          resolve(x)
        })
        this.onRejectedCallbacks.push (()=>{
          let x =  onRejected(this.reason)
          reject(x)
        })
      }
      if(this.status === 'fulfilled'){
          let x = onResolved(this.value)
          resolve(x)
      }
      if(this.status === 'rejected'){
          let x = onRejected(this.value)
          reject(x)
      }
    })
  }    

Maybe functor is very simple, onResolved and onRejected conduct some filtering.

to sum up

Promise is a concept very difficult to understand, but the core idea is always functor.

Meanwhile, on the basis functor added some asynchronous implementations. Asynchronous implementation is a more cost point of brain cells, the bold font take the time to think more about thinking, come on!

Reference links: Promise of functional programming of the fantasy drifting

Guess you like

Origin www.cnblogs.com/chenwenhao/p/11775122.html