打字稿异步/等待不起作用

Posted

技术标签:

【中文标题】打字稿异步/等待不起作用【英文标题】: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"
    ]

【问题讨论】:

【参考方案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 来说真的很有帮助。感谢您的所有回答。您的两个解决方案都有效,并帮助我了解异步的工作原理。干杯。

以上是关于打字稿异步/等待不起作用的主要内容,如果未能解决你的问题,请参考以下文章

打字稿'可选'(可为空)'?语法不起作用(部分)

打字稿实例不起作用

打字稿RefForwardingComponent不起作用

打字稿重载箭头功能不起作用

打字稿计算的吸气剂不起作用

打字稿导入模块作为变量不起作用