Обещание не разрешить внутри асинхронной функции в промежуточном ПО Express - PullRequest
3 голосов
/ 24 сентября 2019

Этот начинает становиться у меня под кожей ...

Я сейчас играю с Firebase и функциями и сделал очень простой API с промежуточным программным обеспечением express в качестве *. 1003 *

Итак, у меня есть этот маршрут:

...

app.get('/getAuthUrl', async (req, res) => {
  const s: sessionManagement.ISessionManagement = 
    sessionManagement.SessionFactory.createSession(
      functions.config().aproxy.session.mode, req, db)

  // ...this work
  const getback = req.query.getback;
  await db.collection('tokens').doc('getback').set({getback});

  // this not?!
  s.setReturnURL(req.query.getback);

  res.setHeader('Cache-Control', 'private');
  res.status(200).json(new Message(redirectUri));
})

Сначала я использую 2 строки под комментарием «... эта работа», и это сработало;запись URL в базу данных Firestore.Пока все хорошо.

Тогда я решил проявить фантазию и решил использовать фабрику объектов для управления тем фактом, что с помощью сеанса Express на локальном хосте выполняются функции (с эмулятором) на одном порту и угловом интерфейсе.с другой вызывала некоторую головную боль при управлении сессиями.Короче говоря, я установил фабрику, которая будет возвращать мне объект, который будет управлять, если я работал локально или на облачном хостинге Firebase и использовал другую стратегию.

Именно здесь Promise начал не держать их ..обещание!?

Строка s.setReturnURL(.. вызывает этот метод внутри моей фабрики:

export interface ISessionManagement {
    setReturnURL: (value: string) => void
}

export class FirestoreSession implements ISessionManagement {
    private database: FirebaseFirestore.Firestore
    private fingerprint: string

    constructor(database: FirebaseFirestore.Firestore, fingerprint: string) {
        this.database = database
        this.fingerprint = fingerprint
    }

    setReturnURL(value: string) {
        console.log('setReturnURL')
        this.writeDoc(value, 'getback')
    }

    writeDoc(value: string, document: string) {
        (async () => {
            console.log('inside async')
            const doc = this.database.collection('tokens').doc(document).set({value})
            const result = await doc
            console.log(result)
        })().catch(error => {
            console.log(error)
        })
        console.log('finish writeDoc')
    }
}

export class SessionFactory {
    public static createSession(mode: string, req: express.Request, db: FirebaseFirestore.Firestore) : ISessionManagement {
        if (mode === 'fingerprint' ) {
            console.log('fingerprint mode');
            // Use for local testing, since in multiport solution, cookie will not be unique to a session
            return new FirestoreSession(db, fingerPrintMe(req));
        } else {
            // For production
            return new ExpressSession(req);
        }
    }
}

Итак, вот консольный вывод потока выполнения, если используется объект моей фабрики:

✔  functions[app]: http function initialized (http://localhost:5000/myplayground/us-central1/app).
i  functions: Beginning execution of "app"
>  fingerprint mode
>  setReturnURL
>  inside async
>  finish writeDoc
i  functions: Finished "app" in ~1s

Приведенный выше код - моя последняя попытка сделать эту работу.Я попробовал МНОГО вариантов, двигая асинхронное ожидание, но ничего не двигалось!

Чего мне не хватает ???Я чувствую, что ответ заставит меня ползти под каким-то камнем, но мне все равно, мне нужно это забыть :-)

ОБНОВЛЕНИЕ

Поворотыиз-за того, что мне нужно полностью выполнить асинхронизацию / ожидание вплоть до вызова, который возвращает обещание сделать эту работу И ТАКЖЕ, вы не можете ожидать функцию, которая возвращает void, поэтому мне пришлось изменить сигнатуру интерфейса.Так вот фрагмент кода, который работает:

app.get('/getAuthUrl', async (req, res) => {
  ... 

  await s.setReturnURL(req.query.getback)

  ...
})

...

export interface ISessionManagement {
    setReturnURL: (value: string) => any 
}

export class FirestoreSession implements ISessionManagement {

    ...

    async setReturnURL(value: string) {
        await this.writeDoc(value, 'getback')
    }

    ...

    async writeDoc(value: string, document: string) {
        try {
            const doc = await this.database.collection('tokens').doc(document).set({value})
            console.log(doc)
        } catch (error) {
            console.log(error)            
        }
    }
}

1 Ответ

0 голосов
/ 24 сентября 2019
const doc = this.database.collection('tokens').doc(document).set({value})
const result = await doc

Почему бы просто const result = await this.database.collection('tokens').doc(document).set({value})?

`writeDoc(value: string, document: string) {
        (async () => {
            console.log('inside async')
            const doc = this.database.collection('tokens').doc(document).set({value})
            const result = await doc
            console.log(result)
        })().catch(error => {
            console.log(error)
        })
        console.log('finish writeDoc')
    }`

Во-первых, writedoc не является обещанием и его не ожидают.Внутренняя асинхронная функция также не ожидается, поэтому, как только выполнение приостанавливается, остальная часть функции продолжается.Таким образом, он будет выполнен, а остальная часть внутренней асинхронной функции будет поставлена ​​в очередь для следующего цикла событий.Тогда все возвращается и выходит.

Сделайте writedoc async и дождитесь его и внутренней асинхронной функции.

...