كيفية استخدام ملاحظة يمكن ملاحظتها داخل `الفلتر`؟

2

افترض أن لدي بنية دليل مشابهة لما يلي:

foo
|
+---one
|   +---tmp
|
+---two
|
+---three
    |
    +---tmp

أريد الحصول على قائمة الدلائل الفرعية تحت foo الذي لديه tmp (sub) دليل فرعي تحته. لدي الكود التالي الذي يفعل ذلك:

const { bindNodeCallback, from } = require('rxjs');
const { map, flatMap, filter } = require('rxjs/operators');
const { readdir, access, accessSync, constants: { F_OK, R_OK }} = require('fs');
const { join } = require('path');

const readdirRx = bindNodeCallback(readdir);

const FOO = './foo';

const result = readdirRx(FOO)
    .pipe(
        // readdir will return an array of files. Convert each
        // file into an observable, and then flatten it.
        flatMap(from),

        // get rid of directories that do not have a `tmp` dir underneath
        filter(dir => {
            try {
                accessSync(join(FOO, dir, 'tmp'), F_OK | R_OK);
                return true;
            } catch (err) {
                return false;
            }
        })
    );
result.subscribe(console.log, console.error, () => console.log('Done!'));
// outputs (correctly):
//   one
//   three
//   Done!

ومع ذلك ، يبدو هذا الرمز فظيعًا بالنسبة لي لأنه (أ) أستخدم استثناءات لتدفق التحكم ، و (ب) هناك تزامن accessSync استدعاء ، وكلاهما يضر بالأداء.

لديّ الرمز التفاعلي التالي الذي يتحقق من نفس الشيء:

const fileExistsAndReadableRx = bindNodeCallback(
    // check if file exists and readable
    (file, cb) => access(file, F_OK | R_OK,
        // call the callback with true if no errors found
        err => cb(!err)
    )
);

ومع ذلك ، لا يمكنني معرفة كيف يمكنني التوصيل fileExistsAndReadableRx في البرنامج أعلاه. هدفي هو إزالة كتلة المحاولة واستخدام fileExistsAndReadableRx بدلا من ذلك لتصفية الدلائل الفرعية التي ليس لديها tmp (sub) دليل فرعي. كيف أقوم بذلك؟

(يرجى ملاحظة أن المهمة الفعلية التي أحاول القيام بها هي عدم قراءة القرص. ما أحاول القيام به هو عملية معقدة غير متزامنة ، وكان عليّ أن أتوصل إلى مثال أبسط لتوضيح مشكلتي).

ما حاولت حتى الآن:

حاولت استخدام map ، ولكنها تنبعث منها تيار من المرصدات ، كما يتوقع المرء:

const result = readdirRx(FOO)
    .pipe(
        flatMap(from),
        map(dir =>
            fileExistsAndReadableRx(join(FOO, dir, 'tmp'))
        )
    );
result.subscribe(console.log, console.error, () => console.log('Done!'));
// Outputs:
//   Observable { _isScalar: false, _subscribe: [Function] }
//   Observable { _isScalar: false, _subscribe: [Function] }
//   Observable { _isScalar: false, _subscribe: [Function] }
//   Done!

لذا فكرت ، أعرف! سأستخدم flatMap لتسطي المرصد. يجب أن ينتج عن ذلك ثلاث قيم منطقية تنبعث في النهاية من تلك المرصدات . لكن ذلك لم ينجح أيضا. تنبعث فقط قيمة واحدة:

const result = readdirRx(FOO)
    .pipe(
        flatMap(from),
        flatMap(dir =>
            fileExistsAndReadableRx(join(FOO, dir, 'tmp'))
        )
    );
result.subscribe(console.log, console.error, () => console.log('Done!'));
// Outputs:
//   true
//   Done!

تعديل:

حاولت IngoBurk الصورة الجواب ، ولكن أن تنتج قيمة منطقية واحدة. لا قائمة سلاسل كما أتوقع:

const result = readdirRx(FOO)
    .pipe(
        flatMap(from),
        flatMap(dir => fileExistsAndReadableRx(join(FOO, dir, 'tmp'))
            .pipe(
                filter(Boolean),
                map(() => dir),
            )
        ),
    );
result.subscribe(console.log, console.error, () => console.log('Done!'));
// Outputs:
//   true
//   Done!

1 إجابة

2
افضل جواب

يمكنك فعل شيء كهذا:

readdirRx(FOO)
  .pipe(
    flatMap(from),
    flatMap(dir => fileExistsAndReadableRx(join(FOO, dir, 'tmp'))
      .pipe(
        catchError(res => of(res)),
        filter(Boolean),
        map(() => dir),
      )
    ),
  )

يفترض ذلك fileExistsAndReadableRx عائدات Observable<boolean> . filter(Boolean) هو مجرد اختصار لـ filter(v => !!v) .

الحيلة هنا هي في الأساس ما جربته ، وهو تعيين (كل) مسطح لكل دليل إلى التحقق الملحوظ لمجلد tmp. ثم نستخدم تلك النتيجة لتصفية تلك التي لا تطابقها ثم نعيدها إلى الدليل بدلاً من تلك النتيجة المتوسطة.

يمكنك مشاهدته عمليًا هنا: https://rxviz.com/v/d8djbkRO

you'd probably want to use cb(null, !err) to invoke the callback in fileExistsAndReadableRx

:مؤلف

أسئلة ذات صلة

فوق
قائمة طعام