【问题标题】:Typescript async/await not working打字稿异步/等待不起作用
【发布时间】:2018-03-08 18:10:07
【问题描述】:

我对目标 es2017 的打字稿上的 async/await 有疑问。以下是我的代码:

我的 route.ts :

method: 'POST',
        config: {            
            auth: {
                strategy: 'token',        
            }
        },
        path: '/users',
        handler: (request, reply) {

    let { username, password } = request.payload;

    const getOperation = User
    .findAll({
        where: {
            username: username
        }
    })
    .then(([User]) => {
        if(!User) {
            reply({
                error: true,
                errMessage: 'The specified user was not found'
            });
            return;
        }

        let comparedPassword = compareHashPassword(User.password, password);
        console.log(comparedPassword);

        if(comparedPassword) {
            const token = jwt.sign({
                username,
                scope: User.id

            }, 'iJiYpmaVwXMp8PpzPkWqc9ShQ5UhyEfy', {
                algorithm: 'HS256',
                expiresIn: '1h'
            });

            reply({
                token,
                scope: User.id
            });
        } else {
            reply('incorrect password');
        }
    } )
    .catch(error => { reply('server-side error') });

};

我的 helper.ts :

export async function compareHashPassword(pw:string, originalPw:string) {
    console.log(pw);
    console.log(originalPw);
    let compared = bcrypt.compare(originalPw, pw, function(err, isMatch) {
        if(err) {
                return console.error(err);
        }
        console.log(isMatch);
        return isMatch;
        });

    return await compared;
}

此身份验证路由应该在用户登录时返回 JWT 令牌。但这里的问题是即使我输入有效密码登录函数 compareHashPassword 总是返回未定义。

例如当我用 json 字符串调用 api 时

{
  "username": "x",
  "password": "helloword"
}

当我使用 console.log() 进行跟踪时,日志是:

$2a$10$Y9wkjblablabla -> hashed password stored in db
helloword 
Promise {
  <pending>,
  domain: 
   Domain {
     domain: null,
     _events: { error: [Function: bound ] },
     _eventsCount: 1,
     _maxListeners: undefined,
     members: [] } }
true

也许这只是我对使用 async/await 和 typescript 缺乏了解。注意我的环境是:

node : v8.6.0
typescript : v2.5.2
ts-node : v3.3.0
my tsconfig.json //
{
    "compilerOptions": {
        "outDir": "dist",
        "target": "es2017",
        "module": "commonjs",
        "removeComments": true,
        "types": [
            "node"
        ],
        "allowJs": true,
        "moduleResolution": "classic"
    },
    "exclude": [
        "node_modules"
    ]
}

【问题讨论】:

    标签: node.js typescript asynchronous async-await sequelize.js


    【解决方案1】:

    为了使 async/await 工作,异步函数必须返回 Promise。此外,您必须以这种方式使用 await 关键字调用 async

    你只能在异步函数中调用 await,所以我将它封装在一个异步函数中

    const someFunc = async function() {
        return new Promise((resolve, reject) => { 
            setTimeout(resolve, 100, true);
        });
    };
    
    (async () => {
         const result = await someFunc(); // true
    })();
    

    您在compareHashPassword 声明中以及您的称呼方式中不满足任何这些规则。

    这就是我将如何重写您的代码:

    export async function compareHashPassword(pw:string, originalPw:string) {
        return new Promise((resolve, reject) => {
            bcrypt.compare(originalPw, pw, function(err, isMatch) {
                if(err) {
                    reject(err);
                }
                console.log(isMatch);
                resolve(isMatch);
            });
        });
    }
    
    // and call it this way
    (async () => {
         const compared = await compareHashPassword(pw, originPw);
    })()
    

    看看这篇异步等待博客文章: https://ponyfoo.com/articles/understanding-javascript-async-await

    还有这篇关于 Promises 的博文: https://developers.google.com/web/fundamentals/primers/promises

    正如@Patrick Roberts 提到的,您可以使用util.promisify 将异步回调样式函数转换为Promise,这是node 8.xx,否则您可以使用具有类似功能的bluebird 包。

    希望对你有帮助

    【讨论】:

    • 目前,您只能在异步函数中调用 await 根据规范,总是就是这样,只是说。
    • 我觉得这很可悲,虽然我没有检查 v8 中的实现本身。感谢您的提示,我会更新我的答案
    • 顺便说一下,在您的第一个示例中,Promise.resolve(...) 是多余的。您所要做的就是return trueasync 函数将隐式强制它成为一个已解决的承诺。
    • 我不知道,所以明确地返回一个 Promise 只需要在回调样式异步调用时完成?
    • 现在你的new Promise() 不再是多余的了,但我个人更喜欢这样写setTimeout(resolve, 100, true); 只是为了思考~
    【解决方案2】:

    由于您的目标是 ES2017,让我们清理您的代码,从更简单的 helper.ts 开始:

    import { promisify } from 'util' // you'll thank me later
    
    const compare = promisify(bcrypt.compare)
    
    export async function compareHashPassword(pw:string, originalPw:string) {
        console.log(pw);
        console.log(originalPw);
        return compare(originalPw, pw);
    }
    

    现在是route.ts

    handler: async (request, reply) => {
      let { username, password } = request.payload;
    
      try {
        const [user] = await User.findAll({
          where: {
            username: username
          }
        })
    
        if(!user) {
          reply({
            error: true,
            errMessage: 'The specified user was not found'
          });
    
          return;
        }
    
        let match = await compareHashPassword(user.password, password);
    
        console.log(match);
    
        if (match) {
          const token = jwt.sign({
            username,
            scope: User.id
          }, 'iJiYpmaVwXMp8PpzPkWqc9ShQ5UhyEfy', {
            algorithm: 'HS256',
            expiresIn: '1h'
          });
    
          reply({
            token,
            scope: user.id
          });
        } else {
          reply('incorrect password');
        }
      } catch (error) {
        reply('server-side error')
      }
    }
    

    希望我已经根据您提供的代码匹配了您想要完成的任务。如果此更新后的代码有问题,请在 cmets 中告诉我。

    【讨论】:

    • 哇,这对 node.js 来说真的很有帮助。感谢您的所有回答。您的两个解决方案都有效,并帮助我了解异步的工作原理。干杯。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 2017-05-11
    • 1970-01-01
    • 2019-03-18
    • 2018-05-03
    • 2016-10-20
    • 1970-01-01
    相关资源
    最近更新 更多