Promise的deferred对象详解
基础知识
简单说,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() 方法暴露给外部以添加自定义逻辑。
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 对象的状态更为灵活。仍然是状态的改变只有一次,之后的更改会忽略。
评论