好吧,我不打算回答 - 但我 was challenged。
很容易利用 Promise 的内置功能来免费获得这种排队。以下是这种转换的工作方式:
- 我们将回调 API 转换为带有 Promise 子类的新对象上的 Promise。
- 我们将所有承诺的方法添加到子类本身 - 所以它链接。
- 我们告诉子类执行
then 中的所有方法,因此它们将排队,因为then 是promise 的排队机制。
注意:我在这里写的 promisify 和 promisifyAll 方法 - 你应该抓住 NPM - 许多好的和快速的用法都需要一个 Promise 构造函数。
首先,我们需要一个方法,converts a callback API to promises:
// F is a promise subclass
function promisify(fn) { // take a function
return function(...args) { // return a new one with promises
return new F((resolve, reject) => { // that returns a promise
// that calls the original function and resolves the promise
fn.call(this, ...args, (err, data) => err ? reject(err) : resolve(data));
});
};
}
现在,让我们承诺整个对象:
function promisifyAll(obj) {
const o = {};
for(const prop in obj) {
if(!(obj[prop].call)) continue; // only functions
o[prop] = promisify(obj[prop]).bind(obj);
}
return o;
}
到目前为止,还没有什么新鲜事,很多 NPM 库都这样做了——现在为了神奇的 Promise——让我们创建一个在 then 中的原始对象上执行函数的方法:
function whenReadyAll(obj) {
const obj2 = {}; // create a new object
for(const prop in obj) { // for each original object
obj2[prop] = function(...args) {
// return a function that does the same thing in a `then`
return this.then(() => obj[prop](...args));
};
}
return obj2;
}
现在,让我们总结一下
function liquidate(obj) {
const promised = promisifyAll(obj); // convert the object to a promise API
class F extends Promise {} // create a promise subclass
Object.assign(F.prototype, whenReadyAll(promised)); // add the API to it
return promised; // return it
// previous code here
}
就是这样,如果我们希望示例是自包含的(同样,promis 和 promisifyAll 通常由库提供):
function liquidate(obj) {
const promised = promisifyAll(obj);
class F extends Promise {}
Object.assign(F.prototype, whenReadyAll(promised)); // add the API
return promised;
function whenReadyAll(obj) {
const obj2 = {};
for(const prop in obj) {
obj2[prop] = function(...args) {
return this.then(() => obj[prop](...args));
};
}
return obj2;
}
function promisifyAll(obj) {
const o = {};
for(const prop in obj) {
if(!(obj[prop].call)) continue; // only functions
o[prop] = promisify(obj[prop]).bind(obj);
}
return o;
}
function promisify(fn) {
return function(...args) {
return new F((resolve, reject) => {
fn.call(this, ...args, (err, data) => err ? reject(err) : resolve(data));
});
};
}
}
或者使用一个可以承诺的库:
function liquidate(obj) { // 14 LoC
class F extends Promise {}
const promised = promisifyAll(obj, F); // F is the promise impl
Object.assign(F.prototype, whenReadyAll(promised)); // add the API
return promised;
function whenReadyAll(obj) {
const obj2 = {};
for(const prop in obj) {
obj2[prop] = function(...args) {
return this.then(() => obj[prop](...args));
};
}
return obj2;
}
}
没有演示的答案是什么:
var o = { // object with a delay callback method
delay(cb) {
console.log("delay");
setTimeout(() => cb(null), 1000);
}
};
var o2 = liquidate(o); // let's liquidate it
// and we even get `then` for free, so we can verify this works
var p = o2.delay().then(x => console.log("First Delay!")).
delay().
then(x => console.log("Second Delay!"));
// logs delay, then First Delay! after a second,
// then delay and then Second Delay! after a second
将此复制粘贴到您友好的邻居控制台,然后自己查看:)
为了证明这保留了原始对象的状态(如果需要,可以很容易地修改它),让我们添加一个 i 变量并延迟递增它,看看事情是否有效:
var o = { // object with a delay callback method
delay(cb) {
console.log("delay", this.i++);
setTimeout(() => cb(null), 1000);
},
i: 0
};
var o2 = liquidate(o); // let's liquidate it
// and we even get `then` for free, so we can verify this works
var p = o2.delay().then(x => console.log("First Delay!")).
delay().
then(x => console.log("Second Delay!", o.i));
//logs:
// delay 0
// First Delay!
// delay 1
// Second Delay! 2