为什么 .then() 从未在此 Node JS 示例中执行,即使 Promise 已解决?

Why is .then() never executed in this Node JS example, even though Promise is resolved?

我是节点的新手,正在学习 Ryan Lewis 关于高级使用 AWS Javascript SDK 的优秀课程。我根据说明编写的代码运行良好,它甚至连接到 AWS 并按预期创建了一个安全组。之后,预计将解决返回的承诺并继续创建密钥对,最后创建实例。如果有错误,预计会被捕获。

但是,使用接近末尾的 .then().catch() 语句传递到 promise 中的解析(或拒绝)函数中的代码永远不会执行,这不是预期的。

我试过了:

这是我的代码:

// Imports
const AWS = require('aws-sdk')
const proxy = require('proxy-agent')
const helpers = require('./helpers')

AWS.config.update({
  region: 'eu-central-1'
})

console.log(AWS.config)

// Declare local variables
const ec2 = new AWS.EC2()
const sgName = 'hamster_sg'
const keyName = 'hamster_key'

// Create functions
function createSecurityGroup(sgName) {
  const params = {
    Description: sgName,
    GroupName: sgName
  }

  return new Promise((resolve, reject) => {
    ec2.createSecurityGroup(params, (err, data) => {
      if (!err) {
        const params = {
          GroupId: data.GroupId,
          IpPermissions: [
            {
              IpProtocol: 'tcp',
              FromPort: 22,
              ToPort: 22,
              IpRanges: [
                {
                  CidrIp: '0.0.0.0/0'
                }
              ]
            },
            {
              IpProtocol: 'tcp',
              FromPort: 3000,
              ToPort: 3000,
              IpRanges: [
                {
                  CidrIp: '0.0.0.0/0'
                }
              ]
            }
          ]
        }
        ec2.authorizeSecurityGroupIngress(params, err => {
          console.log('Creating Security Group.')
          if (!err) {
            console.log('Calling Resolve.')
            resolve
          } else {
            reject(err)
          }
        })
      } else {
        reject(err)
      }
    })
  })
}

function createKeyPair(keyName) {
  const params = {
    KeyName: keyName
  }

  return new Promise((resolve, reject) => {
    ec2.createKeyPair(params, (err, data) => {
      if (!err) {
        resolve(data)
      } else {
        reject(err)
      }
    })
  })
}

function createInstance(sgName, keyName) {
  const params = {
    ImageId: 'ami-026d3b3672c6e7b66',
    InstanceType: 't2.micro',
    KeyName: keyName,
    MaxCount: 1,
    MinCount: 1,
    SecurityGroups: [sgName],
    UserData:
      'IyEvYmluL2Jhc2gKY3VybCAtLXNpbGVudCAtLWxvY2F0aW9uIGh0dHBzOi8vcnBtLm5vZGVzb3VyY2UuY29tL3NldHVwXzgueCB8IHN1ZG8gYmFzaCAtCnN1ZG8geXVtIGluc3RhbGwgLXkgbm9kZWpzCnN1ZG8geXVtIGluc3RhbGwgLXkgZ2l0CmdpdCBjbG9uZSBodHRwczovL2dpdGh1Yi5jb20vdGl0dXNuL2hhbXN0ZXJjb3Vyc2UuZ2l0CmNkIGhiZmwKbnBtIGkKbnBtIHJ1biBzdGFydAo='
  }

  return new Promise((resolve, reject) => {
    ec2.runInstances(params, (err, data) => {
      if (!err) {
        resolve(data)
      } else {
        reject(err)
      }
    })
  })
}

// Do all the things together
createSecurityGroup(sgName)
  .then(
    () => {
      console.log('SecurityGroup Created.')
      return createKeyPair(keyName)
    },
    err => {
      console.error('Failed to create instance with:', err)
    }
  )
  .then(helpers.persistKeyPair)
  .then(() => {
    console.log('Keypair Created.')
    return createInstance(sgName, keyName)
  })
  .then(data => {
    console.log('Created instance with:', data)
  })
  .catch(err => {
    console.error('Failed to create instance with:', err)
  })

setInterval(function() {
  return console.log("I'm still running!")
}, 1000)

这是输出:

Creating Security Group.
Calling Resolve.
I'm still running!
I'm still running!
I'm still running!
I'm still running!
I'm still running!

节点版本为 10.16.0

当我在打印 "Calling Resolve." 的行上的 IntelliJ 中设置断点时,我看到以下内容:

这就是我有点迷茫的地方。我看不到 resolve 函数是否设置正确。有什么办法吗?但更重要的是:我错过了什么?看起来我真的没有做任何特别的事情(除了可能省略所有分号,这是 eslint 和 prettier 让我做的)。所以问题很简单:为什么所有靠近代码末尾的 then() 调用都没有执行,即使我调用 resolve 很好?非常感谢任何帮助。

resolve改为resolve()

    ec2.authorizeSecurityGroupIngress(params, err => {
      console.log('Creating Security Group.')
      if (!err) {
        console.log('Calling Resolve.')
        resolve
      } else {
        reject(err)
      }

所以它变成:

    ec2.authorizeSecurityGroupIngress(params, err => {
      console.log('Creating Security Group.')
      if (!err) {
        console.log('Calling Resolve.')
        resolve()     // <===== change here
      } else {
        reject(err)
      }

您必须实际调用该函数。如果没有括号,只需将 resolve 放入您的代码中就什么也做不了。


仅供参考,通常认为 "promisify" 你的函数在外部(创建单独的 functions/methods 和 return 一个承诺)是一种更简洁的编码风格,与它们的使用分开,所以你的主要编码逻辑和控制流仅显示承诺操作,而不是内联承诺和回调的混合。

此外,对于遵循参数 (err, data) 的回调的 node.js 异步调用约定的函数(这只是您正在使用的部分异步函数),您可以使用 util.promisify() 来创建你的 functions/methods 的 promisified 版本,而无需对每个版本进行手动编码。