定时承诺解决在之前与时间解决一次后立即返回



我在这里的措辞上有点挣扎,但要点是我使用返回对象的 Promise.race (如下所示(。大多数时候,至少有一些承诺会崩溃,但这是故意的。这只是意味着未找到产品。为了避免承诺返回空白,我使用 try catch 块来启动一个新的 15 秒定时承诺。这可以防止 promise 返回空白,让正确完成的最快函数将其对象返回到 Promise.race。当使用 Windows 10 在 NodeJS 10 中进行测试时,这似乎工作得很好,但是当我将其移植到运行 NodeJS 8 和 Ubuntu 18.04 的 Linux 服务器时,我遇到了一些奇怪的行为。Promise.race 工作完全正常,直到我在启动 NodeJS 应用程序后首次测试该功能已经过去了 15 秒。当这 15 秒过去后,当我尝试奔向正常承诺时,它会立即返回定时承诺。

我首先要兑现这些承诺。(不确定这是否重要,但这是通过HTTP请求调用的(

let product = await Promise.race([
get_info_meny_joker(bar_code, "meny.no"),
get_info_meny_joker(bar_code, "joker.no"),
get_info_openfoodfacts(bar_code)
])

其中一个看起来像这样

async function get_info_meny_joker(bar_code, link) {
try {
let url = 'https://' + link + '/Sok/?query=' + bar_code
let browser = await puppeteer.launch({args: ['--no-sandbox']})
let page = await browser.newPage()
await page.goto(url, { waitUntil: 'networkidle2' })
let get_link = await page.evaluate(() => document.querySelector('.ws-product__title').getAttribute('href') )
let product_name = await page.evaluate(() => document.querySelector('.ws-product__title').innerText )
let product_amount = await page.evaluate(() => document.querySelector('.ws-product__subtitle').innerText )
let regex = "[0-9]+([gl]+|ml| [gl] | ml |kg| kg)"
let match = product_amount.match(regex)
match = match[0]
/*let regex_index = new RegExp("[A-Za-z]")
let index_match = regex_index.exec(match).index
match = match.splice(index_match, 0, " ")*/
product_amount = match
await page.goto('https://' + link + '/' + get_link, { waitUntil: 'networkidle2' })
const [first_product, second_product] = await page.$$('.ws-collapsable-block__heading');
await page.screenshot({ path: "x.png" })
second_product.click()
await page.screenshot({ path: "y.png" })
let img_url = await page.evaluate(() => document.querySelector('.lazyloaded').attributes[1].value)
// Get a list of all the nutrients found on the page
let nutrients_raw = await page.evaluate(() => {
let nutrients_raw = document.querySelector('.ws-nutritional-content').children
let nutrients = {}
let i = 0
for (let item of nutrients_raw) {
nutrients[i + ""] = item.innerText
i++
}
return nutrients
});
// Pretify the nutrients_raw to a nutrients object
let nutrients = {}
for (let i = 0; i < Object.size(nutrients_raw); i++) {
let s = nutrients_raw[i]
let type = s.slice(0, s.indexOf(':'))
let amount = s.slice(s.indexOf(':') + 2, s.length)
nutrients[type] = amount
}
return new Product(bar_code, product_name, product_amount, img_url, nutrients, link)
} catch (err) {
return await promise
}
}

定时承诺如下所示

let promise = new Promise((resolve, reject) => {
let product = new Product()
product.name = "Could not be located"
setTimeout(() => resolve(product), 15000)
});

重复一遍,我可以 Promise.race 并且它工作得很好,自从我第一次参加比赛以来已经过去了 15 秒。

(对这个问题并不重要,但我理解 Promise.race 函数是从堆栈中完全删除失败的承诺。奇怪的是,它记得已经过去了 15 秒。

您需要在此创建一个新的promise

let promise = new Promise((resolve, reject) => {
let product = new Product()
product.name = "Could not be located"
setTimeout(() => resolve(product), 15000)
});

每次你想使用它。 否则,当您开始使用计时器时,计时器已经运行了一段时间,它将在远小于 15000 毫秒的时间内触发,因为它已经运行了一段时间。 事实上,如果自您创建承诺以来已超过 15000 毫秒,那么它已经被解决,当您在.race()中使用它时,比赛将立即以这个已经解决的承诺结束。

对这个问题并不重要,但我理解 Promise.race 函数是从堆栈中完全删除失败的承诺。奇怪的是,它记得已经过去了 15 秒。

这是不正确的。Promise.race()不会删除任何内容。 任何输掉比赛的承诺都很好。 只是,Promise.race()回归的承诺将在比赛中的第一个承诺结束后立即解决。 其他人继续前进,并将按照自己的时间表完成。


可能你想做的是把它放到一个函数中并调用该函数,只要你想要一个 15000ms 的承诺:

function timeoutPromise(t) {
return new Promise(resolve => {
let product = new Product();
product.name = "Could not be located";
setTimeout(() => resolve(product), t);
});
}

然后,您只需调用此函数即可在想要使用新的超时承诺时调用此函数以获取新承诺,而不是您正在使用的已保存的promise变量。

相关内容

最新更新