hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

这一次,完全明白Promise源码头脑

2019-11-18杂谈搜奇网25°c
A+ A-

关于Promise的源码完成,网上有太多答案,我也看过许多材料,但都不是很邃晓。直到有一天我学完函数式编程之函子的观点,才对Promise源码有了更深入的熟悉。本日,就让我们来从新熟悉一下Promise。

我们晓得,Promise的降生是为了处置惩罚“回调地狱”的题目,它用同步链式的体式格局去处置惩罚异步的嵌套回调。

啥?同步链式?这不就是我们上一节进修的函子的头脑吗?假如对函子有所相识,那末再来进修Promise源码就比较轻易明白了。接下来,我们探讨一下函子和Promise有着如何的关联。

完成一个简朴的Promise函子

先来回忆一下函子Functor的链式挪用:

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都是一个新的对象,这个对象的原型链上有 map 函数。经由历程 map 中通报进去的函数fn去处置惩罚函子保留的数据,用获得的值去生成新的函子。

等等...函子是同步链式,而Promise是异步链式。也就是说上面a的值是异步发生的,那我们该何如传入 this.value 值呢?

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

我们模仿一下经由历程 setTimeout500 毫秒后拿到数据100。实在也很简朴,我们可以传进去一个 resolve 回调函数去处置惩罚这个数据。

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

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

var a = new MyPromise(executor);

解释一下上面的代码:我们将 executor 传入并马上实行,在 resolve 回调函数中我们可以拿到 value 值,我们定义 resolve 回调函数将 value 的值赋给 this.value。

如许我们就轻松的完成了 a 这个对象的赋值。由因而异步获得的,那末我们怎样用要领去处置惩罚这个数据呢?

依据函子的头脑,在拿到数据以后,我们应当让 map 里传入的 fn 函数去处置惩罚数据。由因而异步处置惩罚, resolve 实行后才拿到数据,所以我们定义了一个 callback 函数,在 callback 内里实行 fn。末了把 fn 处置惩罚的效果交给下一个函子的 resolve 保留。

class MyPromise {
   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 MyPromise((resolve) => {
          self.callback = function(){
              let data =  fn(self.value)   
              resolve(data)
           }
       })
   }    
}

new MyPromise(executor).map(add1).map(add1)

同时挪用同一个Promise函子

Promise除了能链式挪用,还能同时挪用,比方:

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

像上面这个同时挪用a这个函子。你会发明,它实际上只实行了c。缘由也很简朴,b先给a的 callback 赋值,然后c又给a的 callback 赋值。所以把b给掩盖掉了就不会实行啦。处置惩罚这个题目很简朴,我们只需要让callback变成一个数组就处置惩罚了。

class MyPromise {
   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);

我们定义了callbacks数组,每次的挪用a的then要领时。都将其存到callbacks数组中。
当回调函数拿到值时,在resolve中遍历实行每一个函数。
假如callbacks是空,forEach就不会实行,这也处置惩罚了之前把错的题目
然后我们进一步改了函子的名字为 MyPromise,将map改成then
简化了return中,let self = this;

增添reject回调函数

我们都晓得,在异步挪用的时刻,我们每每不能拿到数据,返回一个毛病的信息。这一小节,我们对毛病举行处置惩罚。

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)
      })
    })
  }    
}

实在很简朴,就是我们就是在 executor 多通报进去一个 reject
依据异步实行的效果去推断实行 resolve,照样 reject
然后我们在 MyPromise 为 reject 定义出和 resolve 一样的要领
然后我们在 then 的时刻应当传进去两个参数,fn,fn2

这时刻将executor函数封装到asyncReadFile异步读取文件的函数

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);

这就是我们日常平凡封装异步Promise函数的历程,这个历程有无以为在哪见过。细致看下,asyncReadFile 不就是前面我们提到的柯里化。

增添Promise状况

我们定义举行中的状况为pending
已胜利实行后为fulfilled
失利为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);

末了,如今来看传进去的要领 fn(this.value) ,我们需要用上篇讲的Maybe函子去过滤一下。

Maybe函子优化

 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函子很简朴,对onResolved和onRejected举行一下过滤。

总结

Promise是一个很不好明白的观点,但总归中心头脑照样函子。

同时,在函子的基础上增添了一些异步的完成。异步的完成是一个比较费脑细胞的点,把加粗的字体花点时候多思索思索,加油!

参考链接:函数式编程之Promise的奇异漂泊

范例PromiseA+范例完成:这一次,完全弄懂 Promise 道理

  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
这一次,完全明白Promise源码头脑

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282228.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>