无法将超时添加到 Promise.race 的沉重承诺中



我正在使用React Native和Expo开发移动应用程序。我有一个承诺调用GeoFirestore按距离顺序从firebase firestore查询数据,我的应用程序有时会崩溃,因为GeoFirestore查询没有完成。

所以我需要在重promise中添加一个超时,我尝试使用promise。与两个承诺赛跑,一个承诺调用GeoFirestore API,另一个承诺在给定时间后使用SetTimeout拒绝,就像下面的代码(使用无限循环代替实际的GeoFirestore调用,以便它是可执行的)。

然而,我发现setTimeout不会拒绝,即使时间超过给定的时间。

如何为重承诺添加超时?

我猜javascript在单线程上运行,繁重的操作需要一个线程,但计时器任务无法运行…

const makeTimeoutPromise = (timeMs) => new Promise(function(resolve, reject) {
setTimeout(() => reject(`timeout`), timeMs);
});
const heavyOperationPromise = () => new Promise(function(resolve, reject) {
while (true) { } // a very heayy operation. 
resolve();
});
const test = async () => {
try {
console.log('test started');
const result = await Promise.race([makeTimeoutPromise(100), heavyOperationPromise()]);
console.log(`done result=${result}`);
} catch (e) {
console.log(`catch e=${e}`);
}
}
test();
更新:

while(true) {}似乎不是一个好例子,它阻塞了一个线程。

下面是实际代码。GeoQuery。近是我需要在一个承诺中运行,它需要太长时间或让应用程序崩溃取决于center,radius和firestore DB中的数据。

import { GeoFirestore } from 'geofirestore'; // GeoFirestore 3.4.1
getUsersByDistance = async (location, radius) => {
try {
const geofirestore = new GeoFirestore(firebase.firestore());
const activeUsers = geofirestore.collection('users').where('userStatus', '==', 'active');
const query = activeUsers.near({
center: new firebase.firestore.GeoPoint(location.latitude, location.longitude), radius });
const makeTimeoutPromise = (timeMs) => new Promise(function(resolve, reject) {
setTimeout(() => reject('timeout'), timeMs);
});
// set timeout 5 seconds, but the setTimeout doesn't reject sometimes depending on the center, radius and data in firestore DB.
// query.get sometimes takes very long time, sometimes app crash. 
const result = await Promise.race([makeTimeoutPromise(5000), query.get()]);
// Do something with result
} catch (e) {
console.log(e);
}
}

如果重操作不是async,则不会给setTimeout回调从事件循环执行的机会。例如,如果给它喘息的空间,它就会起作用。

function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const makeTimeoutPromise = (timeMs) => new Promise(function(resolve, reject) {
setTimeout(() => reject(`timeout`), timeMs);
});
const heavyOperationPromise = () => new Promise(async function(resolve, reject) {
while (true) {
await sleep(1);
} // a very heayy operation. 
resolve();
});
const test = async () => {
try {
console.log('test started');
const result = await Promise.race([makeTimeoutPromise(100), heavyOperationPromise()]);
console.log(`done result=${result}`);
} catch (e) {
console.log(`catch e=${e}`);
}
}
test();

最新更新