好吧,我不想回答-但是我受到了挑战。
利用promise的内置功能来免费获得这种排队非常容易。这种转换的工作方式如下:
- 我们将回调API转换为具有Promise子类的新对象上的Promise。
- 我们将所有应许的方法添加到子类自身中-从而将其链接。
- 我们告诉子类执行中的所有方法
then
,因此它们将按照then
承诺的排队机制进行排队。
- 我们告诉子类执行中的所有方法
注意: 我在这里写的
promisify和
promisifyAll方法-您应该使用NPM-
很多好的和快速的用法都带有一个promise构造函数。
// F is a promise subclassfunction 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库都在执行此操作-现在是为了兑现承诺-让我们创建一个对原始对象中的对象执行功能的方法
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 pre here}就是这样,如果我们希望示例是独立的(同样,promise和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 worksvar 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 worksvar 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


