【发布时间】:2015-05-04 18:12:06
【问题描述】:
ES6 Promise 很棒。到目前为止,调整我的想法很容易 回调成语。我发现它自然会鼓励更多的模块化代码,并且 当然错误处理更加清晰。
但有几次我遇到的心流情况看起来(?)不像他们 可以很容易地从 nodebacks 转换为 Promise(也许就是这样,但也许我只是对答案视而不见)。因为承诺是不可知的 关于下一个操作(或者即使有一个),它似乎很难使用 Promise 的 API 不仅接受回调,而且 return 它们。
想到的最常见的例子是“完成”回调。它出现在诸如数据库连接之类的东西中,表示“将连接返回到池”,但我也看到它出现在很多其他地方。
function getSomeStupidConnection(cb) {
var conn = /* ... */;
var iNeedToBeToldWhenIAmDone = function() { /* ... */ };
cb(conn, iNeedToBeToldWhenIAmDone);
}
getSomeStupidConnection(function(conn, done) {
/* ... */
conn.doLotsOfStuff(function(soMuchStuff) {
/* stuff! so much fun! */
/* okay conn go away I’m tired */
done();
});
});
这样的流程反转显然不是您希望在您的 API 中拥有的东西 首先,但它就在那里,有时你无法真正避免它。和 回调,您可以将“稍后调用”内部回调传递给原始“外部” 打回来。它并不完全导致关注点的完全分离,但在 至少它又快又简单。
是否有适合这种情况的基于 Promise 的方法?一种说法, “这是解析值——但是当链完成时,也要这样做”?一世 怀疑没有什么与我刚才描述的完全匹配,因为它 真的不可能说一个链条已经“完成”,但也许我错过了一些 模式可以让你接近它而不会弄得一团糟......
编辑:根据目前的反馈,我意识到根本没有办法将这样的 API 包装在真正的 Promise 中,因为您返回的 Promise 将永远无法告诉您任何有关任何后续链式 Promise 的信息它。但是你可以伪造它。扭曲的是结果相当脆弱。它必须假定唯一需要连接对象的then 是紧随其后的那个。承诺的消费者需要了解它是一次性使用的连接,否则这并不明显。因此,我在实践中并不真正推荐它,但为了好奇,这里有一个解决方案,它隐藏done,同时表现为(并最终成为)承诺链:
/* jshint node: true, esnext: true */
'use strict';
// Assume this comes from an external library. It returns a connection and a
// callback to signal that you are finished with the connection.
function getConnectionExternal(cb) {
let connection = 'Received connection.';
let done = () => console.log('Done was called.');
cb(null, connection, done);
}
// Our promisey wrapper for the above
function getConnection() {
let _done;
let promise = new Promise((resolve, reject) => {
getConnectionExternal((err, connection, done) => {
if (err) return reject(err);
_done = (val) => {
done();
return val;
};
resolve(connection);
});
});
let _then = promise.then.bind(promise);
promise.then = (handler) => _then(handler).then(_done, _done);
return promise;
}
// Test it out
getConnection()
.then(connection => {
console.log(connection);
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Finished using connection!');
resolve('This should be after connection closes.');
}, 200);
});
})
.then(msg => console.log(msg))
.catch(err => console.error(err));
控制台打印:
- 已收到连接。
- 使用连接完成!
- 已调用完成。
- 这应该是在连接关闭之后。
【问题讨论】:
-
不适用于 ES6-Promises,但更强大的库通常会提供
.finally()-methods,这正是您所需要的。也可以看看Bluebird manages resources. -
喜欢你的方法名:)
标签: callback promise ecmascript-6 es6-promise