Promise的deferred对象详解

基础知识
简单说,deferred 对象就回调函数解决方案。在英语中,defer的意思是"延迟",所以 deferred 对象的含义就是"延迟"到未来某个点再执行。所以也叫延迟对象。
我们先看一个例子,等待某个异步操作完成去做一些事情:
let p = new Promise((resolve, reject) => {setTimeout(() => {console.log('完成')resolve(1)}, 1000)})// 等待定时器完成输出okp.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 = resolvedeferred.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延迟对象,deferlet 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 = resolvedeferred.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 对象的状态更为灵活。仍然是状态的改变只有一次,之后的更改会忽略。
评论
