Rx.ReplaySubject:如何延迟"next()"



忽略块:要么我错了,要么威士忌开始起作用了。(我也不想排除我会变笨的可能性。很抱歉。)

预期:

我本来希望ReplaySubject每2秒返回一个值,因为我(每次)要等两秒钟才能调用next()

结果:

结果是等待2秒,但随后所有值都被同时输出

有问题的代码在这里:

import { ReplaySubject } from 'rxjs';
export const rs$: ReplaySubject<number> = new ReplaySubject();
rs$.subscribe({
next: (data) => console.log(data),
error: (error) => console.warn(error),
complete: () => console.log('ReplaySubject completed'),
});
const fakeAPIValuesOne: Array<number> = [7, 11, 13];
fakeAPIValuesOne.forEach(async (entry: number) => {
await wait(2000);  // <--- Why does wait() not work?
rs$.next(entry);
});
function wait(milliseconds: number) {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
}

问题:

我到底做错了什么?

如果你想尝试一下:https://stackblitz.com/edit/rxjs-wpnqvq?file=index.ts

编辑1:

SetTimeout也没有任何作用。以下代码与上述代码完全相同:

fakeAPIValuesOne.forEach((value: number) => {
setTimeout(() => {
rs$.next(value);
}, 2000);
});

我想知道next()如何覆盖这里的所有延迟?

编辑2

问题已解决,正确答案已标记,谢谢!您需要以下详细信息来运行根级别等待ts文件。

package.json

请注意类型部分:

{
"name": "playground",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"start": "nodemon index.ts",
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"rxjs": "^7.5.5",
"ts-node": "^10.7.0",
"typescript": "^4.8.0-dev.20220507"
},
"type": "module"
}

nodemon.json

请考虑以下配置以避免错误:TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"

{
"execMap": {
"ts": "node --loader ts-node/esm"
}
}

最后但并非最不重要的tsconfig.json

{
"compilerOptions": {
"module": "ESNext",
"target": "ESNext",
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"isolatedModules": true,
"noEmit": true,
"strict": true,
"lib": ["esnext", "DOM"]
}
}

以下注释摘自此处的mozilla web文档

注意:forEach需要一个同步函数。

forEach不等待承诺。确保您了解使用promise(或异步函数)作为forEach时的含义回调。

所以这个问题与ReplaySubject无关,只是不能将forEach用于这个用例。

干杯

编辑:已解决

import { ReplaySubject } from "rxjs";
export const rs$ = new ReplaySubject();
rs$.subscribe({
next: (data) => console.log(data),
error: (error) => console.warn(error),
complete: () => console.log("ReplaySubject completed"),
});
const fakeAPIValuesOne = [7, 11, 13];
// That won't work:
// fakeAPIValuesOne.forEach(async (entry: number) => {
//   await wait(2000);
//   rs$.next(entry);
// });

// That will work
for (const element of fakeAPIValuesOne) {
await wait(2000);
rs$.next(element);
}
function wait(milliseconds: number) {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
}

我认为值得一提的是,您不应该(通常)期望它起作用。

考虑以下内容:

wait(2000);
wait(2000);
wait(2000);
console.log("Hello");

"你好"将立即打印到控制台。不会等6秒钟。

如果你把它们放在一个循环中,这不会改变。

for (const n of [1,2,3]) {
wait(2000);
}
console.log("Hello");

这也将打印";你好"马上


如果不使用.then()await,标准行为是不会等待。一些API(当然)会代表您执行等待,但预期的行为是它不会。

你需要这样写:

await wait(2000);
await wait(2000);
await wait(2000);
console.log("Hello");

现在您将等待6秒钟,然后再打印";你好"到控制台。


现在看看这个:

const createPromise = async (v) => {
await wait(2000);
console.log("Hello From createPromise: ", v);
}
createPromise(1);
createPromise(2);
createPromise(3);
console.log("Hello");

你会注意到这并没有什么不同。这将立即打印Hello,然后2秒后所有承诺都将解析并打印

Hello
// 2 seconds wait
Hello From createPromise: 1
Hello From createPromise: 2
Hello From createPromise: 3

你会注意到他们没有一个人在等着对方。这是承诺的预期行为。您需要使用await.then才能实际等待承诺的结果。

你需要写:

await createPromise(1);
await createPromise(2);
await createPromise(3);
console.log("Hello");

这两个循环做相同的事情(正如预期的那样,它们不会等待)

for (const n of [1,2,3]) {
createPromise(n);
}
[1,2,3].forEach(n => createPromise(n))
console.log("Hello");

同样,您将看到打印的第一件事是"Hello",因为您永远不会等待这些承诺中的任何一个得到解决。

你确实在等待内心的wait(2000)承诺,但你从不等待外在的createPromise()承诺。所以你当然不会等他们:)

for (const n of [1,2,3]) {
await createPromise(n);
}

相关内容

  • 没有找到相关文章

最新更新