RxJS等待上一个执行完成

时间:2019-06-28 09:08:52

标签: javascript rxjs

好,所以我是RxJ的新手,我不知道有什么事情。 我需要实现图像处理,在该图像处理中,用户一次添加多个图像,并且对于每个图像,必须执行以下操作:

  1. 在网络工作者中生成图像缩略图
  2. 将图像和缩略图上传到服务器

但是我不希望一次生成所有缩略图,而是希望它们依次生成。这是我尝试的方法:https://codesandbox.io/s/funny-mountain-tm0jj?expanddevtools=1&fontsize=14

我还将代码粘贴到这里:

import { of } from "rxjs";
import { map } from "rxjs/operators";

const imageObservable = of(1, 2, 3, 4, 5);

function generateThumbnail(image) {
  console.log(`Generating thumbnail ${image}`);
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(`Finished generating thumbnail ${image}`);
      resolve({
        image,
        thumbnail: `This is a thumbnail of image ${image}`
      });
    }, 1500);
  });
}

async function upload(imagePromise) {
  const image = await imagePromise;
  console.log("Uploading", image);
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("Finished uploading", image);
      resolve();
    }, 1500);
  });
}

imageObservable.pipe(map(generateThumbnail)).subscribe(upload);

我希望RxJS等待上一个generateThumbnail才能执行当前调用(这就是为什么它返回一个promise对象的原因),并且还要等待上一个upload以便执行当前调用(因此upload也返回了promise)。我不知道如何实现这一目标。任何RxJS忍者都想帮助我吗?

2 个答案:

答案 0 :(得分:2)

要实现以下目标:

  1. 缩略图的生成应顺序进行顺序很重要 =>使用 concatMap
  2. 上传缩略图后应立即进行上传
  3. 可以并行完成上传顺序不重要 =>使用地图

所以最终的代码可能是

imageObservable
  .pipe(
    // preserve orders and wait for previous observable
    concatMap(generateThumbnail), 

    // map the generate
    map(upload)
  )
  .subscribe();
  

注意:上传不会等待generateThumbnail承诺,因为这应该由concatMap本身处理。

async function upload(image) {
  console.log(`[upload] start ${image.image}`);
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(`[upload] done ${image.image}`);
      resolve();
    }, 1000);
  });
}

答案 1 :(得分:1)

您只希望生成缩略图是连续的,还是要生成第二个缩略图就需要等待第一个缩略图的上传完成?

如果您不想等待上传,只需将它们连在一起即可:

import { of, from, } from 'rxjs';
import { concatMap } from 'rxjs/operators';

const imageObservable = of(1, 2, 3, 4, 5);

function generateThumbnail(image) {
    console.log(`Generating thumbnail ${image}`);
    return new Promise(resolve => {
        setTimeout(() => {
            console.log(`Finished generating thumbnail ${image}`);
            resolve({
                image,
                thumbnail: `This is a thumbnail of image ${image}`
            });
        }, 1500);
    });
}

async function upload(imagePromise) {
    const image = await imagePromise;
    console.log('Uploading', image);
    return new Promise(resolve => {
        setTimeout(() => {
            console.log('Finished uploading', image);
            resolve();
        }, 1500);
    });
}

// imageObservable.pipe(map(generateThumbnail)).subscribe(upload);

imageObservable.pipe(concatMap(image => from(generateThumbnail(image)))).subscribe();

concatMap可以满足您的需求,我只是使用Observable创新运算符从您的Promise中提取了一个from,我认为这不是必需的。但是,使用RxJ时,通常更容易使用Observables而不是Promises

function generateThumbnail(image): Observable<any> {
    console.log(`Generating thumbnail ${image}`);
    return from(
        new Promise(resolve => {
            setTimeout(() => {
                console.log(`Finished generating thumbnail ${image}`);
                resolve({
                    image,
                    thumbnail: `This is a thumbnail of image ${image}`
                });
            }, 1500);
        })
    );
}

编辑: 你可以试试吗?

imageObservable
    .pipe(
        concatMap(image => generateThumbnail(image)),
        concatMap(image => upload(image))
    )
    .subscribe();