问题描述
this.route.params.pipe(
concatMap((param) => {
const ein = param['nonprofit-id'];
return this.nonprofitService.getNonprofit(ein).pipe(
concatMap((nonprofit) => {
this.nonprofit = nonprofit;
const ratingID = nonprofit.currentrating?.ratingID ? nonprofit.currentrating.ratingID : -1;
return this.nonprofitService.getratingForNonprofit(ein,ratingID).pipe(
concatMap((nonprofitrating) => {
this.nonprofitrating = nonprofitrating;
const causeID = this.nonprofit?.cause?.causeID ? this.nonprofit?.cause?.causeID : 0;
return this.nonprofitService.getSimilarNonprofits(causeID);
})
);
})
);
})
).subscribe((response) => {
this.similarNonprofits = response;
});
我想知道以上是否是在 Angular RxJS 中链接 concatMaps 的正确方法。另外两个调用依赖于正在检索的“非营利”,以便可以返回其对象。可以同时检索评级和类似非营利组织,所以我想有一些方法可以做到这一点,而无需将这些 concatMaps 相互嵌套。
解决方法
如果您需要使用所有以前的值,通常会以嵌套越来越多的链结束,但在这种情况下,它似乎已经太复杂了,因此您可以将每个内部 Observable const addActivityWithCountries = async(req,res) => {
const activity = await Activity.create({
actId: req.body.actId,name: req.body.name,typeId: req.body.typeId,season: req.body.season,difficulty: req.body.difficulty,duration: req.body.duration,countries: req.body.countries
},{
include: [Country]
}).then((activity) => {
res.json(activity)
}).catch(err => console.log(err))
放入一个数组(或对象)中,例如以下内容:
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "Base64.h"
#include "esp_camera.h"
const char* ssid = "***"; //your network SSID
const char* password = "***"; //your network password
const char* myDomain = "script.google.com";
String myScript = "/macros/s/********/exec"; //Replace with your own url
String myFilename = "filename=ESP32-CAM.jpg";
String mimeType = "&mimetype=image/jpeg";
String myImage = "&data=";
int waitingTime = 30000; //Wait 30 seconds to google response.
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
void setup()
{
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG,0);
Serial.begin(115200);
delay(10);
WiFi.mode(WIFI_STA);
Serial.println("");
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid,password);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.println("STAIP address: ");
Serial.println(WiFi.localIP());
Serial.println("");
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
config.jpeg_quality = 10; //10-63 lower number means higher quality
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x",err);
delay(1000);
ESP.restart();
}
sensor_t * s = esp_camera_sensor_get();
s->set_brightness(s,0); // -2 to 2
s->set_contrast(s,0); // -2 to 2
s->set_saturation(s,0); // -2 to 2
s->set_special_effect(s,0); // 0 to 6 (0 - No Effect,1 - Negative,2 - Grayscale,3 - Red Tint,4 - Green Tint,5 - Blue Tint,6 - Sepia)
s->set_whitebal(s,1); // 0 = disable,1 = enable
s->set_awb_gain(s,1 = enable
s->set_wb_mode(s,0); // 0 to 4 - if awb_gain enabled (0 - Auto,1 - Sunny,2 - Cloudy,3 - Office,4 - Home)
s->set_exposure_ctrl(s,1); // 0 = disable,1 = enable
s->set_aec2(s,0); // 0 = disable,1 = enable
s->set_ae_level(s,0); // -2 to 2
s->set_aec_value(s,300); // 0 to 1200
s->set_gain_ctrl(s,1); // 0 = disable,1 = enable
s->set_agc_gain(s,0); // 0 to 30
s->set_gainceiling(s,(gainceiling_t)0); // 0 to 6
s->set_bpc(s,0); // 0 = disable,1 = enable
s->set_wpc(s,1); // 0 = disable,1 = enable
s->set_raw_gma(s,1); // 0 = disable,1 = enable
s->set_lenc(s,1); // 0 = disable,1 = enable
s->set_hmirror(s,0); // 0 = disable,1 = enable
s->set_vflip(s,0); // 0 = disable,1 = enable
s->set_dcw(s,1 = enable
s->set_colorbar(s,0); // 0 = disable,1 = enable
s->set_framesize(s,FRAMESIZE_UXGA);
}
boolean enviar = true;
void loop() {
//if(enviar) {
saveCapturedImage();
enviar = false;
delay(60000);
//}
}
void saveCapturedImage() {
Serial.println("Connect to " + String(myDomain));
WiFiClientSecure client;
if (client.connect(myDomain,443)) {
Serial.println("Connection successful");
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
delay(1000);
ESP.restart();
return;
}
char *input = (char *)fb->buf;
char output[base64_enc_len(3)];
String imageFile = "";
for (int i=0;i<fb->len;i++) {
base64_encode(output,(input++),3);
if (i%3==0) imageFile += urlencode(String(output));
}
String Data = myFilename+mimeType+myImage;
esp_camera_fb_return(fb);
Serial.println("Send a captured image to Google Drive.");
client.println("POST " + myScript + " HTTP/1.1");
client.println("Host: " + String(myDomain));
client.println("Content-Length: " + String(Data.length()+imageFile.length()));
client.println("Content-Type: application/x-www-form-urlencoded");
client.println();
client.print(Data);
int Index;
for (Index = 0; Index < imageFile.length(); Index = Index+1000) {
client.print(imageFile.substring(Index,Index+1000));
}
Serial.println("Waiting for response.");
long int StartTime=millis();
while (!client.available()) {
Serial.print(".");
delay(100);
if ((StartTime+waitingTime) < millis()) {
Serial.println();
Serial.println("No response.");
//If you have no response,maybe need a greater value of waitingTime
break;
}
}
Serial.println();
while (client.available()) {
Serial.print(char(client.read()));
}
} else {
Serial.println("Connected to " + String(myDomain) + " failed.");
}
client.stop();
}
//https://github.com/zenmanenergy/ESP8266-Arduino-Examples/
String urlencode(String str)
{
String encodedString="";
char c;
char code0;
char code1;
char code2;
for (int i =0; i < str.length(); i++){
c=str.charAt(i);
if (c == ' '){
encodedString+= '+';
} else if (isalnum(c)){
encodedString+=c;
} else{
code1=(c & 0xf)+'0';
if ((c & 0xf) >9){
code1=(c & 0xf) - 10 + 'A';
}
c=(c>>4)&0xf;
code0=c+'0';
if (c > 9){
code0=c - 10 + 'A';
}
code2='\0';
encodedString+='%';
encodedString+=code0;
encodedString+=code1;
//encodedString+=code2;
}
yield();
}
return encodedString;
}
显然,您不必解开作为参数传递给连续 map()
的每个数组,但我希望您明白这一点。
继续@martin 的回答,我建议使用 forkJoin
将最后两个 concatMap
组合到一个请求中,因为它们不相互依赖。这也将并行触发请求,并可能有助于提高性能(尽管微乎其微)。
我还用 nullish coalescing operator ??
替换了三元运算符。
this.route.params.pipe(
concatMap((param: any) => {
const ein = param['nonprofit-id'];
return this.nonprofitService.getNonprofit(ein).pipe(
map((nonprofit) => ([ein,nonprofit]))
);
}),concatMap(([ein,nonprofit]) =>
forkJoin([
this.nonprofitService.getRatingForNonprofit(ein,(nonprofit.currentRating?.ratingID ?? -1)),this.nonprofitService.getSimilarNonprofits(ein,(this.nonprofit?.cause?.causeID ?? 0))
]).pipe(
map(([nonprofitRating,similarNonprofits]) => ([
nonprofit,nonprofitRating,similarNonprofits
]))
)
)
).subscribe({
next: ([nonprofit,similarNonprofits]) => {
this.nonprofit = nonprofit;
this.nonprofitRating = nonprofitRating;
this.similarNonprofits = similarNonprofits;
},error: (error: any) => {
// handle error
}
});
您还可以定义具有属性的对象,以避免对多个元素使用解构语法。