重复async函数直到为true



我有一个async函数,用于检查订单(checkOrderStatus()(的状态。我想重复这个函数,直到它返回"FILLED""CANCELED",然后在另一个函数中使用这个返回值来决定继续或停止代码。每个订单在成为"FILLED""CANCELED"之前都会经历不同的状态,因此需要重复checkOrderStatus()函数(它是API调用(。

我现在拥有的是,重复checkOrderStatus()函数:

const watch = filter => {
return new Promise(callback => {
const interval = setInterval(async () => {
if (!(await filter())) return;
clearInterval(interval);
callback();
}, 1000);
});
};
const watchFill = (asset, orderId) => {
return watch(async () => {
const { status } = await checkOrderStatus(asset, orderId);
console.log(`Order status: ${status}`);
if (status === 'CANCELED') return false;
return status === 'FILLED';
});
};

然后,我从另一个函数调用watchFill(),在那里我想检查它的返回值(truefalse(,如果是true,则继续代码,如果false:,则停止代码

const sellOrder = async (asset, orderId) => {
try {
const orderIsFilled = await watchFill(asset, orderId);

if (orderIsFilled) {
//… Continue the code (status === 'FILLED'), calling other async functions …
}
else {
//… Stop the code
return false;
}
}
catch (err) {
console.error('Err sellIfFilled() :', err);
}
};

然而,这是行不通的。我可以通过watchFill()中的console.log看到终端中的状态正在更新,但它从未停止,最重要的是,无论watchFill()返回的值变成什么,sellOrder()orderIsFilled变量中的值都不会更新。

我如何才能实现期望的行为?

watch从不使用任何值调用resolve(在原始代码中,这被错误地命名为callback()(,因此const orderIsFilled = await watchFill(asset, orderId);不可能使用除undefined之外的任何内容填充orderIsFilled

如果将await filter()的结果保存在变量中并将其传递给callbackcallback(result)一样,您的代码似乎应该可以工作。

也就是说,可以通过使用循环和编写一个简单的wait函数来简化代码。通过这种方式,您可以返回一个值(比弄清楚如何/何时调用resolve更自然(,使new Promise模式远离逻辑,避免处理setInterval和与之相关的记账。

const wait = ms =>
new Promise(resolve => setTimeout(resolve, ms))
;
const watch = async (predicate, ms) => {
for (;; await wait(ms)) {
const result = await predicate();

if (result) {
return result;
}
}
};
/* mock the API for demonstration purposes */
const checkOrderStatus = (() => {
let calls = 0;
return async () => ({
status: ++calls === 3 ? "FILLED" : false
});
})();
const watchFill = (asset, orderId) =>
watch(async () => {
const {status} = await checkOrderStatus();
console.log(`Order status: ${status}`);
return status === "CANCELLED" ? false : status === "FILLED";
}, 1000)
;
const sellOrder = async () => {
try {
const orderIsFilled = await watchFill();
console.log("orderIsFilled:", orderIsFilled);
}
catch (err) {
console.error('Err sellIfFilled() :', err);
}
};
sellOrder();

您可以使用这样的递归功能:

const checkOrderStatus = async () => {
// ... function does some work ...
await someOtherFunction() // you can use here the other async function as well
// ... function does some more work after returning from await ...
if(/* if status is FILLED or CANCELED */) {
// return true or false or some info about response for your needs
} else {
checkOrderStatus();
}
}
// this will response back when status will be FILLED or CANCELED
await checkOrderStatus();

如果filterfalse解析,则watch函数在第一次调用后清除间隔计时器。setInterval也不等待异步函数完成执行,因此您必须自己创建一个循环。试试这个:

const delay = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds));
const watch = async check => {
while (true) {
if (await check()) {
return;
}
await delay(1000);
}
};

因为watch只有在check成功时才能解析,所以不可能失败,所以您不需要检查它(这可能是代码中的错误(:

const sellOrder = async (asset, orderId) => {
try {
await watchFill(asset, orderId);

//… Continue the code (status === 'FILLED'), calling other async functions …
}
catch (err) {
console.error('Err sellIfFilled() :', err);
}
};

p-wait-for包含了一个很好的实现。你可以这样使用:

import pWaitFor from 'p-wait-for';
const watchFill = (asset, orderId) => pWaitFor(async () => {
const { status } = await checkOrderStatus(asset, orderId);
console.log(`Order status: ${status}`);
if (status === 'CANCELED') return false;
return status === 'FILLED';
}, {
interval: 1000,
leadingCheck: false
});

最新更新