Promise.then () 'e eşdeğer RxJS dizisi?


84

Söz vererek çok şey geliştirirdim ve şimdi RxJS'ye geçiyorum. RxJS belgesi, söz zincirinden gözlemci sırasına nasıl geçileceğine dair çok net bir örnek sağlamıyor.

Örneğin, genellikle birden çok adım içeren söz zincirini yazarım.

// a function that returns a promise
getPromise()
.then(function(result) {
   // do something
})
.then(function(result) {
   // do something
})
.then(function(result) {
   // do something
})
.catch(function(err) {
    // handle error
});

Bu söz zincirini RxJS tarzında nasıl yeniden yazmalıyım?

Yanıtlar:


81

Veri akışı için (eşdeğer then):

Rx.Observable.fromPromise(...)
  .flatMap(function(result) {
   // do something
  })
  .flatMap(function(result) {
   // do something
  })
  .subscribe(function onNext(result) {
    // end of chain
  }, function onError(error) {
    // process the error
  });

Bir söz, ile gözlemlenebilir hale getirilebilir Rx.Observable.fromPromise.

Bazı vaat operatörlerinin doğrudan çevirisi vardır. Örneğin RSVP.all, veya jQuery.whenile değiştirilebilir Rx.Observable.forkJoin.

Verileri eşzamansız olarak dönüştürmenize ve vaatlerle yapamayacağınız veya yapmanın çok zor olacağı görevleri gerçekleştirmenize izin veren bir grup operatörünüz olduğunu unutmayın. Rxjs, tüm güçlerini eşzamansız veri dizileri ile ortaya çıkarır (sıra, yani 1'den fazla eşzamansız değer).

Hata yönetimi için konu biraz daha karmaşıktır.

  • orada yakalamak ve nihayet operatörler de
  • retryWhen hata durumunda bir dizinin tekrarlanmasına da yardımcı olabilir
  • onErrorişlev ile abonenin kendisindeki hataları da halledebilirsiniz .

Kesin anlambilim için, web'de bulabileceğiniz belgelere ve örneklere daha derin bir göz atın veya burada belirli sorular sorun.

Bu, Rxjs ile hata yönetiminde daha derine inmek için kesinlikle iyi bir başlangıç ​​noktası olacaktır: https://xgrommx.github.io/rx-book/content/getting_started_with_rxjs/creating_and_querying_observable_sequences/error_handling.html


Her zaman gözlemlenebilir sıranın subscribe () ile bittiğini görüyorum. Bu sadece gözlemlenebilir nesnenin bir işlevi olduğu için, bunu yapmak için herhangi bir neden var mı? Diziyi başlatma işlevi mi?
Haoliang Yu

aynen öyle. Abone olunan herhangi bir gözlemci yoksa, gözlemlenebilir cihazınız herhangi bir veri yaymaz, böylece herhangi bir veri akışı görmezsiniz.
user3743222

7
Şuna bir göz atmanızı tavsiye ederim: gist.github.com/staltz/868e7e9bc2a7b8c1f754 . Resmi belgeden daha lezzetli olabilir.
user3743222

3
Promise.thenziyade .flatMapdaha .map.
Tamas Hegedus

1
Bilginize bunda tam olarak eşdeğer değildir Promise3. ve sürüm hataları thentarafından yakalanmış olacağını catch. Burada değiller.
mik01aj

35

Daha modern bir alternatif:

import {from as fromPromise} from 'rxjs';
import {catchError, flatMap} from 'rxjs/operators';

fromPromise(...).pipe(
   flatMap(result => {
       // do something
   }),
   flatMap(result => {
       // do something
   }),
   flatMap(result => {
       // do something
   }),
   catchError(error => {
       // handle error
   })
)

Ayrıca işe bütün bunlar için yapmanız gerekenler olduğuna dikkat subscribebu borulu için Observableyerde, ama uygulamanın başka parçası ele varsayıyorum.


RxJS'de çok yeniyim, ancak burada yalnızca bir olayın ilk akışıyla uğraştığımız ve bu mergeMap()nedenle aslında birleştirecek hiçbir şeyin olmadığı göz önüne alındığında, bu durumda da aynı şeyi kullanarak concatMap()veya switchMap(). Bunu doğru mu anladım ...?
Dan King

8

Mayıs 2019'u RxJs 6 kullanarak güncelleyin

Yukarıda verilen cevapları kabul edin, netlik sağlamak için RxJs v6 kullanarak bazı oyuncak verileri ve basit vaatlerle (setTimeout ile) somut bir örnek eklemek istedim .

Sadece aktarılan kimliği (şu anda sabit kodlu 1) var olmayan bir şeye güncelleyerek hata işleme mantığını da çalıştırın. Önemli olan, aynı zamanda kullanımını not ofile catchErrormesajında.

import { from as fromPromise, of } from "rxjs";
import { catchError, flatMap, tap } from "rxjs/operators";

const posts = [
  { title: "I love JavaScript", author: "Wes Bos", id: 1 },
  { title: "CSS!", author: "Chris Coyier", id: 2 },
  { title: "Dev tools tricks", author: "Addy Osmani", id: 3 }
];

const authors = [
  { name: "Wes Bos", twitter: "@wesbos", bio: "Canadian Developer" },
  {
    name: "Chris Coyier",
    twitter: "@chriscoyier",
    bio: "CSS Tricks and CodePen"
  },
  { name: "Addy Osmani", twitter: "@addyosmani", bio: "Googler" }
];

function getPostById(id) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const post = posts.find(post => post.id === id);
      if (post) {
        console.log("ok, post found!");
        resolve(post);
      } else {
        reject(Error("Post not found!"));
      }
    }, 200);
  });
}

function hydrateAuthor(post) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const authorDetails = authors.find(person => person.name === post.author);
      if (authorDetails) {
        post.author = authorDetails;
        console.log("ok, post hydrated with author info");
        resolve(post);
      } else {
        reject(Error("Author not Found!"));
      }
    }, 200);
  });
}

function dehydratePostTitle(post) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      delete post.title;
      console.log("ok, applied transformation to remove title");
      resolve(post);
    }, 200);
  });
}

// ok, here is how it looks regarding this question..
let source$ = fromPromise(getPostById(1)).pipe(
  flatMap(post => {
    return hydrateAuthor(post);
  }),
  flatMap(post => {
    return dehydratePostTitle(post);
  }),
  catchError(error => of(`Caught error: ${error}`))
);

source$.subscribe(console.log);

Çıkış Verileri:

ok, post found!
ok, post hydrated with author info
ok, applied transformation to remove title
{ author:
   { name: 'Wes Bos',
     twitter: '@wesbos',
     bio: 'Canadian Developer' },
  id: 1 }

Temel kısım, basit taahhüt kontrol akışı kullanan aşağıdakilere eşdeğerdir:

getPostById(1)
  .then(post => {
    return hydrateAuthor(post);
  })
  .then(post => {
    return dehydratePostTitle(post);
  })
  .then(author => {
    console.log(author);
  })
  .catch(err => {
    console.error(err);
  });

1

Doğru anladıysam, değerleri tüketmeyi kastediyorsunuz, bu durumda sbuscribe ie

const arrObservable = from([1,2,3,4,5,6,7,8]);
arrObservable.subscribe(number => console.log(num) );

Ek olarak, gösterildiği gibi toPromise () kullanarak gözlemlenebilir olanı bir söze dönüştürebilirsiniz:

arrObservable.toPromise().then()

0

eğer getPromisefonksiyonu bir dere boru ortasında yapmanız gerekir işlevlerinden biri haline basit şal bunu mergeMap, switchMapya concatMap(genellikle mergeMap):

stream$.pipe(
   mergeMap(data => getPromise(data)),
   filter(...),
   map(...)
 ).subscribe(...);

Akışınızı ile başlatmak istiyorsanız, getPromise()onu fromişleve sarın :

import {from} from 'rxjs';

from(getPromise()).pipe(
   filter(...)
   map(...)
).subscribe(...);

0

Az önce öğrendiğim kadarıyla, bir flatMap'te bir sonuç döndürürseniz, bir dize döndürseniz bile, bunu bir Array'e dönüştürür.

Ama bir Gözlenebilir döndürürseniz, o gözlemlenebilir bir dizge döndürebilir;


0

Ben böyle yaptım.

Önceden

  public fetchContacts(onCompleteFn: (response: gapi.client.Response<gapi.client.people.ListConnectionsResponse>) => void) {
    const request = gapi.client.people.people.connections.list({
      resourceName: 'people/me',
      pageSize: 100,
      personFields: 'phoneNumbers,organizations,emailAddresses,names'
    }).then(response => {
      onCompleteFn(response as gapi.client.Response<gapi.client.people.ListConnectionsResponse>);
    });
  }

// caller:

  this.gapi.fetchContacts((rsp: gapi.client.Response<gapi.client.people.ListConnectionsResponse>) => {
      // handle rsp;
  });

Sonra (ly?)

public fetchContacts(): Observable<gapi.client.Response<gapi.client.people.ListConnectionsResponse>> {
    return from(
      new Promise((resolve, reject) => {
        gapi.client.people.people.connections.list({
          resourceName: 'people/me',
          pageSize: 100,
          personFields: 'phoneNumbers,organizations,emailAddresses,names'
        }).then(result => {
          resolve(result);
        });
      })
    ).pipe(map((result: gapi.client.Response<gapi.client.people.ListConnectionsResponse>) => {
      return result; //map is not really required if you not changing anything in the response. you can just return the from() and caller would subscribe to it.
    }));
  }

// caller

this.gapi.fetchContacts().subscribe(((rsp: gapi.client.Response<gapi.client.people.ListConnectionsResponse>) => {
  // handle rsp
}), (error) => {
  // handle error
});

yan etki : geri aramayı gözlemlenebilir hale getirdikten sonra değişiklik tespiti de çalışmaya başladı .
Anand Rockzz

0

Promise.then () 'e eşdeğer RxJS dizisi?

Örneğin

function getdata1 (argument) {
        return this.http.get(url)
            .map((res: Response) => res.json());
    }

    function getdata2 (argument) {
        return this.http.get(url)
            .map((res: Response) => res.json());
    }

    getdata1.subscribe((data1: any) => {
        console.log("got data one. get data 2 now");
        getdata2.subscribe((data2: any) => {
            console.log("got data one and two here");
        });
    });
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.