Внешняя функция KOA/node.js отвечает до завершения обратного вызова

Во-первых, извиняюсь за название, ничего лучше не придумал. Я думал, что понимаю Node.js/KOA, по крайней мере, основы, но теперь я начинаю чувствовать, что мне не хватает некоторых основ.

Взгляните на следующий код:

    router.put("/", 
    parse, 
    async function (ctx, next) {

        // do something

        await next();
    },
    async function (ctx, next) {

        // do something

        await next();
    },
    async function (ctx, next) {

        if (some condition) {

            gm(imageBuffer)
                .quality(80)
                .write(profile_path, async function (err) {
                    gm(imageBuffer)
                        .resize(60, 60)
                        .quality(80)
                        .write(chat_path,async function (err) {

                            await next(); // HERE 1

                        });
                });

        } else {
            await next();
        }

        // HERE 2
    },
    async function (ctx, next) {

        responses.success(ctx, "Success");
    }
);

Так что это все о. Те, кто знаком с фреймворком KOA, сразу увидят, что здесь происходит. Моя проблема начинается/заканчивается в третьем async function. Итак, что я пытаюсь сделать здесь, это некоторые манипуляции с изображениями (сохранение). gm является асинхронным, но, как вы можете видеть из кода, я использую анонимные функции обратного вызова, и я пытаюсь добиться того, чтобы последний async function вызывался, когда gm заканчивает через await next(); // HERE 1.

Но что на самом деле происходит (насколько я понимаю)... gm запускается асинхронно... и // HERE 2 срабатывает, и поскольку ничего нет, конец функции, KOA возвращает ответ 404 по умолчанию. Я просто не могу понять, почему это так и как это побороть. Что я действительно хочу, так это то, что когда обратный вызов завершается, await next(); // HERE 1 вызывается, и я могу вернуть ответ об успешном завершении. await next(); // HERE 1, конечно, вызывают (в конце концов), но слишком поздно, потому что KOA уже отвечает 404.

Если есть кто-то, кто может и хочет объяснить, что именно здесь происходит, спасибо.


person repca    schedule 21.05.2017    source источник


Ответы (1)


Насколько я вижу, ваш подход на самом деле не соответствует шаблону асинхронного ожидания: функция async должна «ожидать» асинхронную часть. Затем это должно вернуть обещание. Таким образом, вы должны инкапсулировать свой обратный вызов в promise. Что-то вроде этого может работать (не тестировать, просто чтобы показать концепцию):

function gmAsync(){
    return new Promise(function(resolve,reject){
          gm(imageBuffer)
                .quality(80)
                .write(profile_path, async function (err) {
                    gm(imageBuffer)
                        .resize(60, 60)
                        .quality(80)
                        .write(chat_path,async function (err) {

                            resolve(....whatever....);

                        });
                });
    });
}

и тогда ваша асинхронная функция может выглядеть так:

async function (ctx, next) {
    if (some condition) {
        await gmAsync()
        next()
    } else {
        await next();
    }
},
...

Имеет смысл?

person Sebastian Hildebrandt    schedule 22.05.2017
comment
Это именно то, что я искал. Спасибо за помощь. - person repca; 31.05.2017