我有一个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()
,在那里我想检查它的返回值(true
或false
(,如果是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()
的结果保存在变量中并将其传递给callback
和callback(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();
如果filter
用false
解析,则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
});