聊聊promise

关于promise,网上的介绍很多,可以说是callback hell的解决方案。由于使用了promise一段时间了,想了很多,这里稍微聊聊。了解promise的原理和用法之后,写程序的时候就会容易很多。

首先,关于promise的方法,显而易见,有两个then和catch

var promise = {
  then:function(){},
  catch:function(){}
}

then用于成功后的回调,而catch则返回err事件。而这两个方法是如何工作的呢?

最初
我们先定义一个todo方法

function todo(cb){
  var v = "this is cb"
  cb(v)
}

假如我们要直接调用的话,是这样的

todo(function(v){
  console.log("got it :",v)
})

如果一直这样cb下去,就会陷入cb hell了。如果使用promise的话,应该是这样调用的

function todo(){
  var v = "this is cb"
  return{
    then:function(cb){
      cb(v)
    }
  }
}

todo().then(function(v){
  console.log("got it :",v)
})

解释什么是promise

还是用代码来说话,

function Promise(fn){
  var callback
  this.then = function(cb){
    callback = cb
  }
  function resolve(v){
    setTimeout(function(){
      callback(v)
    },0)
  }
  fn(resolve)
}

function todo(){
  return new Promise(function(resolve){
    var v = "this is cb"
    resolve(v)
  })
}

这里要注意一下resolve之中为什么要用setTimeout。假如不这样做,而是直接

  function resolve(v){
      callback(v)
  }

程序就会报错,因为程序会在this.then之前得到resolve,而这个时候callback还未=cb。至于为什么,只要了解什么是event loop之后就知道了,可以看下https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

promise的状态

我们已经写完了一个简单的promise应用,但是还不够,依旧会碰到许多callback的问题。所以对于promise,需要给他定义两个状态(还有第三个状态rejected,处理失败事件,后面再讨论)
1. pending//等待
2. fulfilled//成功

function Promise(fn){
  var state ="pending"
  var v
  var deferred
  function resolve(newV){
    v = newV
    state ="fulfilled"
    if(deferred){
      handle(deferred)
    }
  }
  function handle(onFulfilled){
    if(state==="pending"){
      deferred = onFulfilled
      return
    }
    onFulfilled(v)
  }
  this.then = function(onFulfilled){
    handle(onFulfilled)
  }
  fn(resolve)
}
function todo(){
  return new Promise(function(resolve){
    request("http://www.baidu.com",function(err,res,body){
       if(!err&&res.statusCode==200) resolve(res)
       else reject(err)
    })
  })
}
todo().then(function(v){
    console.log(v)
})

这里我用了request依赖,比较容易解释关于回调的问题。

这里整个过程是这样的

todo()

  1. Promise,todo
  2. 然后由于todo(),开始运行Promise的方法
  3. state=“pending”,v=undefined,deferred=undefined,resolve,handle,this.then,fn(resolve)
  4. request(“http://www.baidu.com“)

todo().then()

  1. handle(onFulfilled)
  2. if(state===”pending”){….}
  3. 然后等request得到回调之后
  4. if(!err&&res.statusCode==200) resolve(res)
  5. v = newV,state =”fulfilled”,这个时候deferred=onFulfilled = function(){}
  6. handle(deferred)
  7. onFulfilled(v)
  8. console.log(v)

于是乎,我们就得到了请求的结果了,但是,像这样的Promise方法还不能满足我们日常的需要,因为我们一般使用Promise的时候代码看起来应该是这样的:

todo()
    .then(function (v) {
        var s = []
        s.push(v)
        return s
    })
    .then(function (v) {
        s.push(v)
        return s
    })
    .then(function (v) {
        console.log(v)
    })

所以我们需要再改下代码。让每个return 能作为下一个then的输入才行。

但是如何做呢

很显然,我们需要用到递归的想法来实现这样的,每使用一次.then(),实例化一次Promise

function Promise(fn) {
    var state = "pending"
    var v
    var deferred

    function resolve(newV) {
        if(newV && typeof newV.then === 'function') {
            newV.then(resolve);
            return;
        }
        v = newV
        state = "fulfilled"
        if (deferred) {
            handle(deferred)
        }
    }
    function handle(h) {
        if (state === "pending") {
            deferred = h
            return
        }
        if(!h.onFulfilled){
            h.resolve(v)
            return
        }
        var ret =h.onFulfilled(v)
        h.resolve(ret)
    }

    this.then = function (onFulfilled) {
        return new Promise(function(resolve){
            handle({
                onFulfilled:onFulfilled,
                resolve:resolve
            })
        })
    }
    fn(resolve)
}

好了,关于Promise就先聊到这里。关于Pormise的依赖,建议使用bluebird
https://github.com/petkaantonov/bluebird

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值