在调用完整的回调之前,已解决了Observable toPromise

时间:2019-08-22 14:23:56

标签: javascript promise rxjs observable

我想创建一个队列,在该队列中,我总是并行执行两个httpRequest。当一个请求完成时,下一个应该开始,以便总是两个并行运行。 我想合并结果并在所有请求完成后将其整体返回。

我的第一个尝试是创建一个Subject(队列),并在其中使用queue.next(url)传递URL。剧院结束后,我立即完成了本主题。我使用mergeMap将执行一次限制为两个请求(queueObservable)。

我订阅queueObservable并将响应添加到数组(列表)。 然后,我等待queueObservable的承诺,该承诺应在Observable完成时解决。

但是正在发生的是,即使在执行下一个下一个回调之前和在可观察对象完成之前,承诺也会得到解决。

在我的第二次尝试中,我创建了一个新的Promise并在queueObservable的已完成回调中解决它。这种方法很好用,但是我不明白为什么第一种方法不起作用。

你能告诉我吗? 有没有更聪明的解决方案来解决这个问题?

亲切的问候, 大卫

import { of, Subject } from 'rxjs';
import { delay, mergeMap } from 'rxjs/operators';

const testFunction1 = async () => {
    const queue = new Subject();
    const list = [];
    const queueObservable = queue.pipe(mergeMap(val => of(val).pipe(delay(500)), 2));

    queueObservable.subscribe((next) => {
        console.log(next);
        list.push(next);
    }, () => { },
        (complete) => {
            console.log('Observable1 completed');
        });

    queue.next('HTTP1: 1');
    queue.next('HTTP1: 2');
    queue.next('HTTP1: 3');
    queue.next('HTTP1: 4');
    queue.complete();
    await queueObservable.toPromise(); // I expect this to resolve when all values passed the mergeMap pipe.
    return list;
}

const testFunction2 = async () => {
    const list = [];
    await new Promise(resolve => {
        const queue = new Subject();
        const queueObservable = queue.pipe(mergeMap(val => of(val).pipe(delay(500)), 2));

        queueObservable.subscribe((next) => {
            console.log(next);
            list.push(next);
        }, () => { },
            () => {
                console.log('Observable2 completed'); // This gets called when all values passed mergeMap pipe.
                resolve();
            });

        queue.next('HTTP2: 1');
        queue.next('HTTP2: 2');
        queue.next('HTTP2: 3');
        queue.next('HTTP2: 4');
        queue.complete();
    });
    return list;

}
testFunction1().then(res => {
    console.log('Over1: ' + JSON.stringify(res));
});

testFunction2().then(res => {
    console.log('Over2: ' + JSON.stringify(res));
});

编辑: 此图基本上显示了我要归档的内容。当所有其他可观察变量完成时,管道可观察的变量(queueObservable)完成。当我在管道可观察对象上调用toPromise时,它仅应在管道可观察对象完成时解决(至少这是我对toPromise功能的理解)。

enter image description here

2 个答案:

答案 0 :(得分:0)

您能做这样的事(fiddle

const urlsSink = new Subject();
const responses = urlsSink.pipe(bufferCount(2), mergeMap((urls) => {
    return combineLatest(urls.map(url => makeHttpRequest(url)));
}));

然后,您可以订阅responses并将URL推送到urlsSink中。 bufferCount将URL分为两个组。 combineLatest会将两个HTTP观察值合并为一个合并的HTTP观察值。

答案 1 :(得分:0)

这是因为您正在延迟这些值,这些值尚未发出,但是您完成了主题。完成主题后,应兑现诺言。

尝试一下

queueObservable

这将迫使案例1起作用,但这不适合提出请求。

似乎queue的承诺跟随toArray的完成。

您可以使用const queueObservable = from(listOfURL).pipe( mergeMap(val => of(val).pipe(delay(500)), 2), mergeMap(val => fetch(url + val)), toArray(), ); 运算符合并到结果。

const Ajv = require('ajv')
const ajv = new Ajv()

const schema = {
    query: {
        type: 'object',
        required: ['locale'],
        properties: {
            locale: {
                type: 'string',
                minLength: 1,
            },
        },
    },
}

const test = {
    a: 1,
}

const validate = ajv.compile(schema)
const valid = validate(test)
console.log(valid) // TRUE