Promise的deferred對象詳解

基礎知識
簡單說,deferred 對象就回調函數(shù)解決方案。在英語中,defer的意思是"延遲",所以 deferred 對象的含義就是"延遲"到未來某個點再執(zhí)行。所以也叫延遲對象。
我們先看一個例子,等待某個異步操作完成去做一些事情:
let p = new Promise((resolve, reject) => {setTimeout(() => {console.log('完成')resolve(1)}, 1000)})// 等待定時器完成輸出okp.then((res) => {console.log('ok', res)})
我們發(fā)現(xiàn) Promise 和定時器耦合在一起,也就是說定時器必須寫在 Promise 里面,因為需要等待定時器完成修改 Promise 的狀態(tài)。接下來解耦,我們希望外部能控制 Promise 的狀態(tài)。
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 主要是用于內部,用于維護異步模型的狀態(tài);Promise 則作用于外部,通過 then() 方法暴露給外部以添加自定義邏輯。

Promise/Deferred 模式的API接口和抽象模型都十分簡潔。它將業(yè)務中不可變的部分封裝在了 Deferred 中,將可變的部分交給了 Promise。
項目實戰(zhàn)
到目前為止我們已經掌握了 Promise 的 deferred 對象,接下來我們就看看怎么使用吧。
1、減少代碼嵌套
let fs = require('fs');// 實現(xiàn)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 的狀態(tài),回調只想執(zhí)行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個異步操作完成就執(zhí)行回調deferred.promise.then(() => {console.log('ok')})
3、多個異步之間的協(xié)作方案,多個延遲對象配合使用。
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對象實現(xiàn)了 Promise,并且將 resolve 和 reject 方法暴露在了構造函數(shù)外面,Promise 對象的狀態(tài)更為靈活。仍然是狀態(tài)的改變只有一次,之后的更改會忽略。
