JS-按顺序进行链式异步方法,无需回调或修改

我正在尝试向原型添加“默认回调”,如果没有提供原型,该原型将向异步方法分配回调函数(以Promise的形式)。

目标是使类的异步方法链同步运行

Item.async1().async2()....asyncN()

请注意,异步函数本身希望回调,但不会在函数调用中将其作为参数传递(这告诉我,在回调查找失败时该类需要默认行为)

规范指出,我无法直接修改原型方法的行为或副作用。我可以添加原型方法。我们不知道如何实现这些原型方法。

TLDR:在不修改原型方法的情况下,如何链接N个异步方法并确保它们按顺序运行?

顺便说一句:如果我想实现承诺的版本,那么有问题的原型方法将很有帮助,但是看起来我们只限于原始函数调用

回答:

好吧,我不想回答-但是我受到了挑战。

利用promise的内置功能来免费获得这种排队非常容易。这种转换的工作方式如下:

  • 我们将回调API转换为具有Promise子类的新对象上的Promise。
  • 我们将所有应许的方法添加到子类自身中-从而将其链接。

    • 我们告诉子类执行中的所有方法then,因此它们将按照then承诺的排队机制进行排队。

我在这里写的promisifypromisifyAll方法-您应该使用NPM-

很多好的和快速的用法都带有一个promise构造函数。

// 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库都在执行此操作-现在是为了兑现承诺-让我们创建一个对原始对象中的对象执行功能的方法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

}

就是这样,如果我们希望示例是独立的(同样,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 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

以上是 JS-按顺序进行链式异步方法,无需回调或修改 的全部内容, 来源链接: utcz.com/qa/409674.html

回到顶部