Promise的deferred对象详解

c039b8eb33143fddbf0e7ad2424e7958.png

基础知识

简单说,deferred 对象就回调函数解决方案。在英语中,defer的意思是"延迟",所以 deferred 对象的含义就是"延迟"到未来某个点再执行。所以也叫延迟对象。

我们先看一个例子,等待某个异步操作完成去做一些事情:

let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('完成')
    resolve(1)
  }, 1000)
})
// 等待定时器完成输出ok
p.then((res) => {
  console.log('ok', res)
})

我们发现 Promise 和定时器耦合在一起,也就是说定时器必须写在 Promise 里面,因为需要等待定时器完成修改 Promise 的状态。接下来解耦,我们希望外部能控制 Promise 的状态。

let resolveFn // 把resolve保存起来方便外部调用
let p = new Promise((resolve, reject) => {
  resolveFn = resolve
})


setTimeout(() => {
  console.log('完成')
  resolveFn(1)
}, 1000)


p.then((res) => {
  console.log('ok', res)
})

我们通过一个全局变量把 resolve 保存起来方便外部调用,如果需要的话可以再定义一个变量把 reject 保存起来,由于这里未使用所以省略了。

可能需要3个全局变量,为了防止变量冲突,我们最好通过一个对象来保存。

let deferred = {}
deferred.promise = new Promise((resolve, reject) => {
  deferred.resolve = resolve
  deferred.reject = reject
})


setTimeout(() => {
  console.log('完成')
  deferred.resolve(1)
}, 1000)


deferred.promise.then((res) => {
  console.log('ok', res)
})

Promise 和 Deferred 的整体关系,从上面的代码可以看出,Deferred 主要是用于内部,用于维护异步模型的状态;Promise 则作用于外部,通过 then() 方法暴露给外部以添加自定义逻辑。

845a937ff7b8a7093ea563800fdbbb2f.png

Promise/Deferred 模式的API接口和抽象模型都十分简洁。它将业务中不可变的部分封装在了 Deferred 中,将可变的部分交给了 Promise。

项目实战

到目前为止我们已经掌握了 Promise 的 deferred 对象,接下来我们就看看怎么使用吧。

1、减少代码嵌套

let fs = require('fs');


// 实现promise延迟对象,defer
let Deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  })
  return dfd
}


// function read () {
//   return new Promise((resolve, reject) => {
//     fs.readFile('./a.txt', 'utf8', (err, data) => {
//       if (!err) resolve(data)
//     })
//   })
// }
// 减少代码嵌套


function read () {
  let defer = Deferred()
  fs.readFile('./a.txt', 'utf8', (err, data) => {
    if (!err) defer.resolve(data)
  })
  return defer.promise
}


read().then((data) => {
  console.log(data)
})

2、多个地方想控制1个 Promise 的状态,回调只想执行1次。

let deferred = {}
deferred.promise = new Promise((resolve, reject) => {
  deferred.resolve = resolve
  deferred.reject = reject
})
// 异步操作的顺序不确定
setTimeout(() => {
  deferred.resolve()
}, 10 * Math.random())


setTimeout(() => {
  deferred.resolve()
}, 10 * Math.random())


// 只要有1个异步操作完成就执行回调
deferred.promise.then(() => {
  console.log('ok')
})

3、多个异步之间的协作方案,多个延迟对象配合使用。

let Deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  })
  return dfd
}


let d1 = Deferred()
let d2 = Deferred()


Promise.all([d1.promise, d2.promise]).then((res) => {
  console.log(res) // [ 'Fish', 'Pizza' ]
})


d1.resolve( "Fish" )
d2.resolve( "Pizza" )

总结:

Deferred对象实现了 Promise,并且将 resolve 和 reject 方法暴露在了构造函数外面,Promise 对象的状态更为灵活。仍然是状态的改变只有一次,之后的更改会忽略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值