Javascript 承诺 - 为什么这些不起作用
Javascript promises - why aren't these working
我对 Promises 功能进行了以下 mocha 测试,但结果令人困惑。
describe('test promises', () => {
const constPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('11');
}, 500);
});
const constPromise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('2222');
}, 500);
});
const functionPromise = (arg) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${arg} 333333`);
}, 1000);
})
}
const functionPromise2 = (arg) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${arg} 44444444`);
}, 1000);
})
}
it('using async', async () => {
functionPromise(1).then(a => {
console.log(`function promise (then ): ${a}`)
})
const x1 = await functionPromise(2)
console.log(`function promise (await): ${x1}`)
functionPromise2(3).then(a => {
console.log(`function2 promise (then ): ${a}`)
})
// const x2 = await promiseFn()
const x2 = '88 NOT ACTUALLY A PROMISE'
console.log(`function2 NOT A promise: ${x2}`)
constPromise.then(b => {
console.log(`const promise (then ): ${b}`)
})
const a = await constPromise
console.log(`const promise (await): ${a}`)
constPromise2.then(b => {
console.log(`const2 promise (then): ${b}`)
})
// const a2 = await promiseConst2
const a2 = '99 NOT ACTUALLY A PROMISE'
console.log(`const2 NOT A promise: ${a2}`)
})
it('async iife', () => {
(async () => {
functionPromise(3).then(a => {
console.log(`function promise (then): ${a}`)
})
constPromise.then(b => {
console.log(`const promise (then): ${b}`)
});
const x = await functionPromise(4)
// const x = 'NOT ACTUALLY A PROMISE'// await myPromiseFn()
console.log(`function promise (await): ${x}`)
// return myPromise.then(a => console.log(`promise: ${a}`)).catch(e => console.log(`promise error: ${e}`))
const a = await constPromise
console.log(`const promise (await): ${a}`)
})()
})
})
结果是这样的:
/Users/abba/.nvm/versions/node/v12.22.6/bin/node /Users/abba/dev/_tools/updateUsersData/node_modules/mocha/bin/mocha --ui bdd --reporter /Applications/IntelliJ IDEA.app/Contents/plugins/NodeJS/js/mocha-intellij/lib/mochaIntellijReporter.js /Users/abba/dev/_tools/updateUsersData/test/app-spec2.js --grep ^test promises
function promise (then ): 1 333333
function promise (await): 2 333333
function2 NOT A promise: 88 NOT ACTUALLY A PROMISE
const promise (then ): 11
const promise (await): 11
const2 NOT A promise: 99 NOT ACTUALLY A PROMISE
const2 promise (then): 2222
iife const promise (then): 11
以及 Nodejs v12.22.6 我试过 Nodejs 16.8.0。
让我困惑的注意事项:
- 没有
function2 promise (then ): 3
但是有function promise (await): 2
。 await
被要求触发 .then()
似乎从 functionPromise
等效测试。这是为什么?
constPromises
似乎不成立 - 尽管没有 await constPromise2
,但 const2 promise (then): 2222
还是出现了。与函数中的 Promises 相比,变量中 Promises 的行为为何不同?
async iife
测试有一个结果,但是如果我 运行 只有它而没有其他 NONE。这是为什么?
任何更深入的解释将不胜感激。
好吧,这让我有点困惑,但我想通了。这可能有点令人困惑,所以请随时要求更多说明,但我会尽力而为。
记录什么和不记录什么的关键因素是时间的函数。让我们看看测试在做什么以及它们的结果是什么。
第一次测试 - “使用异步”
functionPromise(1).then(a => {
console.log(`function promise (then ): ${a}`)
})
functionPromise returns 一个承诺,但由于我们不等待该承诺(通过说 await functionPromise),代码将继续进行。 .then() 不会阻塞代码流,只会在 promise 被解析后异步调用其中的函数。
const x1 = await functionPromise(2)
console.log(`function promise (await): ${x1}`)
由于您这次正在等待(通过等待)functionPromise 解析,它将等待 promise 解析(基本上等待一秒钟),然后记录下一行。
但请注意,第一个 promise 调用现在也已经解决(就在这个之前)并且会有 运行 解决,之后下一行执行并记录你的第二个结果。
所以现在的日志看起来像
function promise (then ): 1 333333
function promise (await): 2 333333
好吗?接下来是 functionPromise2
functionPromise2(3).then(a => {
console.log(`function2 promise (then ): ${a}`)
})
现在虽然功能相同,但这就是它不记录任何内容的原因。正如我们在第一个承诺中看到的那样,此调用也不等待承诺解决,因此不会立即记录任何内容并移至下一行。,即 -
const x2 = '88 NOT ACTUALLY A PROMISE'
console.log(`function2 NOT A promise: ${x2}`)
因此被添加到日志中。请记住,将记录 functionPromise2 的日志,但在 1 秒后。
所以现在的日志预计是 -
function promise (then ): 1 333333
function promise (await): 2 333333
function2 NOT A promise: 88 NOT ACTUALLY A PROMISE
正如您所展示的那样。
下一个
constPromise.then(b => {
console.log(`const promise (then ): ${b}`)
})
再次。不用等待。所以我们继续前进。什么都没有记录。此日志将在 500 毫秒内 运行,因为那是 constPromise 解析的时间。虽然,就在这之后你打电话给
const a = await constPromise
console.log(`const promise (await): ${a}`)
等待。这将等待 500 毫秒。这允许之前的承诺也得到解决,我们得到 2 个日志
const promise (then ): 11
const promise (await): 11
所以现在登录
function promise (then ): 1 333333
function promise (await): 2 333333
function2 NOT A promise: 88 NOT ACTUALLY A PROMISE
const promise (then ): 11
const promise (await): 11
下一个。
constPromise2.then(b => {
console.log(`const2 promise (then): ${b}`)
})
由于我们没有等待,因此还没有记录任何内容。代码向前移动。
const a2 = '99 NOT ACTUALLY A PROMISE'
console.log(`const2 NOT A promise: ${a2}`)
过了一会儿,
然后这段代码记录
const2 NOT A promise: 99 NOT ACTUALLY A PROMISE
然后在 500 毫秒后 constPromise2 解析并记录
const2 promise (then): 2222
所以日志实际上符合预期。
现在是“async iife”
由于测试用例不是异步的,所以测试用例会同步 运行 里面的函数。
所有行 运行 和测试退出。
现在出现了一些灰色区域,我不是 100% 确定。
const2 promise (then): 2222
iife const promise (then): 11
这些日志发生在测试用例实际完成之后,因为它们正在等待,但由于测试用例本身可能需要大约 500 毫秒才能结束,因此该日志能够进入控制台。也许更高的超时时间可以证明这一理论。
原因是我使用的是 Mocha v3.5.3(最新的是 v9.1.3)。
所以当我使用 Mocha v3.5.3 并且测试是 运行 从终端我们看到:
> ./node_modules/mocha/bin/mocha --timeout 10000 ./test/app-spec2.js
test promises
function promise (then ): 1 333333
function promise (await): 2 333333
function2 NOT A promise: 88 NOT ACTUALLY A PROMISE
const promise (then ): 11
const promise (await): 11
const2 NOT A promise: 99 NOT ACTUALLY A PROMISE
const2 promise (then): 2222
✓ using async (1001ms)
✓ async iife
iife const promise (then): 11
2 passing (1s)
但是当我升级到最新的 Mocha 时,我们看到:
> ./node_modules/mocha/bin/mocha --timeout 10000 ./test/app-spec2.js
test promises
function promise (then ): 1 333333
function promise (await): 2 333333
function2 NOT A promise: 88 NOT ACTUALLY A PROMISE
const promise (then ): 11
const promise (await): 11
const2 NOT A promise: 99 NOT ACTUALLY A PROMISE
const2 promise (then): 2222
✔ using async (1004ms)
✔ async iife
iife const promise (then): 11
2 passing (1s)
function2 promise (then ): 3 44444444
iife function promise (then): 3 333333
iife function promise (await): 4 333333
iife const promise (await): 11
所以你可以看到所有的承诺都在解决。但是,您还可以看到 'missing' 的承诺在测试完成后得到解决。
有趣的是,IntelliJ 似乎在输出后 运行 对输出进行分类(我从未见过)——但这是一个单独的问题。
我尝试添加一个 'done' 方法:
it('using async', async (done) => {
// console.log(`before promise call outside`)
functionPromise(1).then(a => {
console.log(`function promise (then ): ${a}`)
})
...
done()
assert.isTrue(true)
})
但是未对齐仍然存在,我得到一个错误:
Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both
我不明白这是为什么。但是在 Mocha 测试中使用 Promises 是不正常的,我现在不打算继续这样做。我似乎找到了让我继续实际工作的答案。
我不能放过它,需要找出如何解决在测试完成后承诺解决的问题,如问题和我之前的回答 - .
我整理了更多代码来展示如何最好地使用 promises 超时。
describe('test promises', () => {
const timeout=2500
let startTime
beforeEach(() => {
startTime = new Date()
})
afterEach(() => {
const endTime = new Date()
const diff = endTime - startTime
console.log(` time to run test: ${diff} ms`)
})
describe('new tests', () => {
// Both then and await fail for this
const failurePromiseFn = (arg) => {
return new Promise(resolve => {
setTimeout(
resolve(`${arg} - failurePromiseFn`), timeout);
})
}
// Both succeed
const successPromiseFn = (arg) => {
return new Promise(resolve => {
setTimeout(() => {
resolve(`${arg} - successPromiseFn`)
}, timeout);
})
}
describe('these dont work - they finish BEFORE end of test BUT timeout fails', () => {
it('failurePromiseFn - then', (done) => {
// order correct, no timeout
failurePromiseFn(1).then(res => {
console.log(` failurePromiseFn - then: ${res}`)
done()
})
})
it('failurePromiseFn - await', async () => {
// order correct, no timeout
const res = await failurePromiseFn(2)
console.log(` failurePromiseFn - await: ${res}`)
})
})
describe('these work - they finish BEFORE end of test AND timeout succeeds', () => {
it('successPromiseFn - await', async () => {
// order correct, yes timeout
const res = await successPromiseFn(3)
console.log(` successPromiseFn - await: ${res}`)
})
it('successPromiseFn - then', (done) => {
// order not correct, yes timeout
successPromiseFn(4).then(res => {
console.log(` successPromiseFn - then: ${res}`)
done()
})
})
})
describe('other examples from internet', () => {
const delay = t => new Promise(resolve => setTimeout(resolve, t));
it('using delay - then - succeeds', (done) => {
delay(timeout).then(() => {
console.log(' Hello')
done()
});
})
it('using delay - then - fails as no done so timeout fails', () => {
delay(timeout).then(() => {
console.log(' Hello')
});
})
it('using delay - await - succeeds', async () => {
await delay(timeout)
console.log(' Hello')
})
})
})
})
结果是:
test promises
new tests
these dont work - they finish BEFORE end of test BUT timeout fails
failurePromiseFn - then: 1 - failurePromiseFn
✓ failurePromiseFn - then
time to run test: 3 ms
failurePromiseFn - await: 2 - failurePromiseFn
✓ failurePromiseFn - await
time to run test: 0 ms
these work - they finish BEFORE end of test AND timeout succeeds
successPromiseFn - await: 3 - successPromiseFn
✓ successPromiseFn - await (2504ms)
time to run test: 2504 ms
successPromiseFn - then: 4 - successPromiseFn
✓ successPromiseFn - then (2501ms)
time to run test: 2501 ms
other examples from internet
Hello
✓ using delay - then - succeeds (2503ms)
time to run test: 2503 ms
✓ using delay - then - fails as no done so timeout fails
time to run test: 1 ms
Hello
Hello
✓ using delay - await - succeeds (2504ms)
time to run test: 2504 ms
6 passing (10s)
我对 Promises 功能进行了以下 mocha 测试,但结果令人困惑。
describe('test promises', () => {
const constPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('11');
}, 500);
});
const constPromise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('2222');
}, 500);
});
const functionPromise = (arg) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${arg} 333333`);
}, 1000);
})
}
const functionPromise2 = (arg) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${arg} 44444444`);
}, 1000);
})
}
it('using async', async () => {
functionPromise(1).then(a => {
console.log(`function promise (then ): ${a}`)
})
const x1 = await functionPromise(2)
console.log(`function promise (await): ${x1}`)
functionPromise2(3).then(a => {
console.log(`function2 promise (then ): ${a}`)
})
// const x2 = await promiseFn()
const x2 = '88 NOT ACTUALLY A PROMISE'
console.log(`function2 NOT A promise: ${x2}`)
constPromise.then(b => {
console.log(`const promise (then ): ${b}`)
})
const a = await constPromise
console.log(`const promise (await): ${a}`)
constPromise2.then(b => {
console.log(`const2 promise (then): ${b}`)
})
// const a2 = await promiseConst2
const a2 = '99 NOT ACTUALLY A PROMISE'
console.log(`const2 NOT A promise: ${a2}`)
})
it('async iife', () => {
(async () => {
functionPromise(3).then(a => {
console.log(`function promise (then): ${a}`)
})
constPromise.then(b => {
console.log(`const promise (then): ${b}`)
});
const x = await functionPromise(4)
// const x = 'NOT ACTUALLY A PROMISE'// await myPromiseFn()
console.log(`function promise (await): ${x}`)
// return myPromise.then(a => console.log(`promise: ${a}`)).catch(e => console.log(`promise error: ${e}`))
const a = await constPromise
console.log(`const promise (await): ${a}`)
})()
})
})
结果是这样的:
/Users/abba/.nvm/versions/node/v12.22.6/bin/node /Users/abba/dev/_tools/updateUsersData/node_modules/mocha/bin/mocha --ui bdd --reporter /Applications/IntelliJ IDEA.app/Contents/plugins/NodeJS/js/mocha-intellij/lib/mochaIntellijReporter.js /Users/abba/dev/_tools/updateUsersData/test/app-spec2.js --grep ^test promises
function promise (then ): 1 333333
function promise (await): 2 333333
function2 NOT A promise: 88 NOT ACTUALLY A PROMISE
const promise (then ): 11
const promise (await): 11
const2 NOT A promise: 99 NOT ACTUALLY A PROMISE
const2 promise (then): 2222
iife const promise (then): 11
以及 Nodejs v12.22.6 我试过 Nodejs 16.8.0。
让我困惑的注意事项:
- 没有
function2 promise (then ): 3
但是有function promise (await): 2
。 await
被要求触发 .then()
似乎从 functionPromise
等效测试。这是为什么?
constPromises
似乎不成立 - 尽管没有await constPromise2
,但const2 promise (then): 2222
还是出现了。与函数中的 Promises 相比,变量中 Promises 的行为为何不同?async iife
测试有一个结果,但是如果我 运行 只有它而没有其他 NONE。这是为什么?
任何更深入的解释将不胜感激。
好吧,这让我有点困惑,但我想通了。这可能有点令人困惑,所以请随时要求更多说明,但我会尽力而为。 记录什么和不记录什么的关键因素是时间的函数。让我们看看测试在做什么以及它们的结果是什么。
第一次测试 - “使用异步”
functionPromise(1).then(a => {
console.log(`function promise (then ): ${a}`)
})
functionPromise returns 一个承诺,但由于我们不等待该承诺(通过说 await functionPromise),代码将继续进行。 .then() 不会阻塞代码流,只会在 promise 被解析后异步调用其中的函数。
const x1 = await functionPromise(2)
console.log(`function promise (await): ${x1}`)
由于您这次正在等待(通过等待)functionPromise 解析,它将等待 promise 解析(基本上等待一秒钟),然后记录下一行。 但请注意,第一个 promise 调用现在也已经解决(就在这个之前)并且会有 运行 解决,之后下一行执行并记录你的第二个结果。
所以现在的日志看起来像
function promise (then ): 1 333333
function promise (await): 2 333333
好吗?接下来是 functionPromise2
functionPromise2(3).then(a => {
console.log(`function2 promise (then ): ${a}`)
})
现在虽然功能相同,但这就是它不记录任何内容的原因。正如我们在第一个承诺中看到的那样,此调用也不等待承诺解决,因此不会立即记录任何内容并移至下一行。,即 -
const x2 = '88 NOT ACTUALLY A PROMISE'
console.log(`function2 NOT A promise: ${x2}`)
因此被添加到日志中。请记住,将记录 functionPromise2 的日志,但在 1 秒后。
所以现在的日志预计是 -
function promise (then ): 1 333333
function promise (await): 2 333333
function2 NOT A promise: 88 NOT ACTUALLY A PROMISE
正如您所展示的那样。 下一个
constPromise.then(b => {
console.log(`const promise (then ): ${b}`)
})
再次。不用等待。所以我们继续前进。什么都没有记录。此日志将在 500 毫秒内 运行,因为那是 constPromise 解析的时间。虽然,就在这之后你打电话给
const a = await constPromise
console.log(`const promise (await): ${a}`)
等待。这将等待 500 毫秒。这允许之前的承诺也得到解决,我们得到 2 个日志
const promise (then ): 11
const promise (await): 11
所以现在登录
function promise (then ): 1 333333
function promise (await): 2 333333
function2 NOT A promise: 88 NOT ACTUALLY A PROMISE
const promise (then ): 11
const promise (await): 11
下一个。
constPromise2.then(b => {
console.log(`const2 promise (then): ${b}`)
})
由于我们没有等待,因此还没有记录任何内容。代码向前移动。
const a2 = '99 NOT ACTUALLY A PROMISE'
console.log(`const2 NOT A promise: ${a2}`)
过了一会儿, 然后这段代码记录
const2 NOT A promise: 99 NOT ACTUALLY A PROMISE
然后在 500 毫秒后 constPromise2 解析并记录
const2 promise (then): 2222
所以日志实际上符合预期。
现在是“async iife” 由于测试用例不是异步的,所以测试用例会同步 运行 里面的函数。 所有行 运行 和测试退出。
现在出现了一些灰色区域,我不是 100% 确定。
const2 promise (then): 2222
iife const promise (then): 11
这些日志发生在测试用例实际完成之后,因为它们正在等待,但由于测试用例本身可能需要大约 500 毫秒才能结束,因此该日志能够进入控制台。也许更高的超时时间可以证明这一理论。
原因是我使用的是 Mocha v3.5.3(最新的是 v9.1.3)。
所以当我使用 Mocha v3.5.3 并且测试是 运行 从终端我们看到:
> ./node_modules/mocha/bin/mocha --timeout 10000 ./test/app-spec2.js
test promises
function promise (then ): 1 333333
function promise (await): 2 333333
function2 NOT A promise: 88 NOT ACTUALLY A PROMISE
const promise (then ): 11
const promise (await): 11
const2 NOT A promise: 99 NOT ACTUALLY A PROMISE
const2 promise (then): 2222
✓ using async (1001ms)
✓ async iife
iife const promise (then): 11
2 passing (1s)
但是当我升级到最新的 Mocha 时,我们看到:
> ./node_modules/mocha/bin/mocha --timeout 10000 ./test/app-spec2.js
test promises
function promise (then ): 1 333333
function promise (await): 2 333333
function2 NOT A promise: 88 NOT ACTUALLY A PROMISE
const promise (then ): 11
const promise (await): 11
const2 NOT A promise: 99 NOT ACTUALLY A PROMISE
const2 promise (then): 2222
✔ using async (1004ms)
✔ async iife
iife const promise (then): 11
2 passing (1s)
function2 promise (then ): 3 44444444
iife function promise (then): 3 333333
iife function promise (await): 4 333333
iife const promise (await): 11
所以你可以看到所有的承诺都在解决。但是,您还可以看到 'missing' 的承诺在测试完成后得到解决。
有趣的是,IntelliJ 似乎在输出后 运行 对输出进行分类(我从未见过)——但这是一个单独的问题。
我尝试添加一个 'done' 方法:
it('using async', async (done) => {
// console.log(`before promise call outside`)
functionPromise(1).then(a => {
console.log(`function promise (then ): ${a}`)
})
...
done()
assert.isTrue(true)
})
但是未对齐仍然存在,我得到一个错误:
Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both
我不明白这是为什么。但是在 Mocha 测试中使用 Promises 是不正常的,我现在不打算继续这样做。我似乎找到了让我继续实际工作的答案。
我不能放过它,需要找出如何解决在测试完成后承诺解决的问题,如问题和我之前的回答 -
我整理了更多代码来展示如何最好地使用 promises 超时。
describe('test promises', () => {
const timeout=2500
let startTime
beforeEach(() => {
startTime = new Date()
})
afterEach(() => {
const endTime = new Date()
const diff = endTime - startTime
console.log(` time to run test: ${diff} ms`)
})
describe('new tests', () => {
// Both then and await fail for this
const failurePromiseFn = (arg) => {
return new Promise(resolve => {
setTimeout(
resolve(`${arg} - failurePromiseFn`), timeout);
})
}
// Both succeed
const successPromiseFn = (arg) => {
return new Promise(resolve => {
setTimeout(() => {
resolve(`${arg} - successPromiseFn`)
}, timeout);
})
}
describe('these dont work - they finish BEFORE end of test BUT timeout fails', () => {
it('failurePromiseFn - then', (done) => {
// order correct, no timeout
failurePromiseFn(1).then(res => {
console.log(` failurePromiseFn - then: ${res}`)
done()
})
})
it('failurePromiseFn - await', async () => {
// order correct, no timeout
const res = await failurePromiseFn(2)
console.log(` failurePromiseFn - await: ${res}`)
})
})
describe('these work - they finish BEFORE end of test AND timeout succeeds', () => {
it('successPromiseFn - await', async () => {
// order correct, yes timeout
const res = await successPromiseFn(3)
console.log(` successPromiseFn - await: ${res}`)
})
it('successPromiseFn - then', (done) => {
// order not correct, yes timeout
successPromiseFn(4).then(res => {
console.log(` successPromiseFn - then: ${res}`)
done()
})
})
})
describe('other examples from internet', () => {
const delay = t => new Promise(resolve => setTimeout(resolve, t));
it('using delay - then - succeeds', (done) => {
delay(timeout).then(() => {
console.log(' Hello')
done()
});
})
it('using delay - then - fails as no done so timeout fails', () => {
delay(timeout).then(() => {
console.log(' Hello')
});
})
it('using delay - await - succeeds', async () => {
await delay(timeout)
console.log(' Hello')
})
})
})
})
结果是:
test promises
new tests
these dont work - they finish BEFORE end of test BUT timeout fails
failurePromiseFn - then: 1 - failurePromiseFn
✓ failurePromiseFn - then
time to run test: 3 ms
failurePromiseFn - await: 2 - failurePromiseFn
✓ failurePromiseFn - await
time to run test: 0 ms
these work - they finish BEFORE end of test AND timeout succeeds
successPromiseFn - await: 3 - successPromiseFn
✓ successPromiseFn - await (2504ms)
time to run test: 2504 ms
successPromiseFn - then: 4 - successPromiseFn
✓ successPromiseFn - then (2501ms)
time to run test: 2501 ms
other examples from internet
Hello
✓ using delay - then - succeeds (2503ms)
time to run test: 2503 ms
✓ using delay - then - fails as no done so timeout fails
time to run test: 1 ms
Hello
Hello
✓ using delay - await - succeeds (2504ms)
time to run test: 2504 ms
6 passing (10s)