Javascript promise устраняет путаницу

private runMiddlewares(route: Route | ExceptionRoute, request: HttpRequest, response: HttpResponse): Promise<any> {
    return new Promise((resolve, reject) => {
        try {
            route.middlewares.forEach(async (middleware: IMiddleware) => {
                console.log('begin run middleware');
                await middleware.process(request, response);
                console.log('resolve run middleware');
                console.log(request.body);
            });
            console.log('resolve all runMiddlewares');
            resolve();
        } catch (e) {
            reject(e);
        }
    });
}

Я написал эту функцию runMiddlewares, которая в идеале должна разрешить (), когда все middleware.process() разрешены. Я использую функциональность машинописного кода await, но, похоже, она не работает. Я ожидаю, что что-то подобное произойдет внутри route.middlewares.forEach(

  • 'начать запуск промежуточного программного обеспечения'
  • затем ожидает решает
  • 'промежуточное ПО разрешения запуска'

Это продолжается для всех промежуточных программ в цикле forEach, и когда список готов, тогда и только после этого должно быть напечатано «разрешить все runMiddlewares», и, наконец, private runMiddlewares( ... ) должен разрешиться.

Но вместо этого forEach теперь немедленно решается, что предотвращает полное завершение работы всех промежуточных программ.

Как с этим справиться? Я думал, что await позаботится об этом внутри цикла forEach, и только тогда в конце будет вызываться resolve из runMiddlewares. Что мне здесь не хватает?

Возможно, вы используете await внутри цикла foreach. Это также правило eslint: cn.eslint.org/docs/3.0.0/rules/no-await-in-loop, которое рекомендует избегать этого и имеет пример другого подхода.

Bas van Dijk 10.09.2018 09:05

Спасибо, я тоже догадался. Я пришел из опыта работы с C#, и он бы там сработал, поэтому я ожидал, что он будет работать и здесь :) Я написал его с помощью Promise.all, и теперь он работает.

Vishal Anand 10.09.2018 09:10

@VishalAnand Возможно, подумайте о добавлении своего решения в качестве ответа. Это могло бы быть полезно, если бы поделился явным образом.

Cerberus 10.09.2018 09:12

добавляя это сейчас. Благодарность

Vishal Anand 10.09.2018 09:13
1
4
64
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Итак, следуя рекомендации (https://cn.eslint.org/docs/3.0.0/rules/no-await-in-loop), я написал это следующим образом

private runMiddlewares(route: Route | ExceptionRoute, request: HttpRequest, response: HttpResponse): Promise<any> {
    return new Promise(async (resolve, reject) => {
        try {
            const middlewarePromiseArry: any[] = [];
            route.middlewares.forEach((middleware: IMiddleware) => {
                console.log('begin run middleware');
                middlewarePromiseArry.push(middleware.process(request, response));
                // removed the use of await inside of forEach loop following this link: https://cn.eslint.org/docs/3.0.0/rules/no-await-in-loop
                // await middleware.process(request, response);
                // console.log('resolve run middleware');
                // console.log(request.body);
            });

            await Promise.all(middlewarePromiseArry);
            console.log('resolve all runMiddlewares');
            resolve();
        } catch (e) {
            reject(e);
        }
    });
}

С радостью приму дальнейшие ответы и рекомендации / улучшения :)

Ответ принят как подходящий

Вы можете использовать map для создания массива обещаний из вашего промежуточного программного обеспечения. Этот массив обещаний может быть передан в Promise.all, который разрешается, когда каждое отдельное обещание массива было разрешено.

await Promise.all(route.middlewares.map((middleware: IMiddleware) => {
            console.log('begin run middleware');
            const promise = middleware.process(request, response);
            console.log('resolve run middleware');
            console.log(request.body);
            return promise
        });

Или даже компактнее:

runMiddlewares(...) {
  return Promise.all(
    route.middlewares.map((middleware: IMiddleware) => {
      return middleware.process(request, response))
    })
  )
}

просто любопытно, чем это отличается от моего ответа? кроме того, почему асинхронный режим требуется внутри функции карты?

Vishal Anand 10.09.2018 09:19

На самом деле это очень похоже (с точки зрения потока управления). IMHO мой ответ легче меньше кода и легче читать. Например, вам не нужно создавать обещание для Promise.all, и вам не нужно его ждать, поскольку вы все равно возвращаете обещание. Array.prototype.map часто рекомендуется вместо создания новых массивов вручную из циклов / forEach

lipp 10.09.2018 09:26

Другие вопросы по теме