【问题标题】:async await Promise usage blocks forever on awaitasync await Promise 在 await 上的使用永远阻塞
【发布时间】:2018-05-16 01:03:54
【问题描述】:

调用 websocket 连接的事件处理程序 (wss.on) 调用异步函数 sendInitialState()。在那里我调用了一个异步函数 (getMetadata()),它返回一个 Promise,我在其中执行了一些异步操作。我解决了这个承诺,resolve(res) 被调用了,但是程序仍然阻塞等待,也就是说,console.log(metadata) 永远不会被调用。

wss.on('connection', (ws) => {

    sendInitialState();
});

const sendInitialState = async (ws) => {

    console.log('Sending initial state!');
    const metadata = await getMetadata();
    console.log('metadata:', metadata);
};

const getMetadata = async () => {

    return new Promise((resolve, reject) => {
        MongoClient.connect(url, (err, db) => {
            if (err) {reject(err);}
            else {
              db.collection("meta").findOne({type: 'a'}, (err, res) => {
                if (err) reject(err);
                else {
                    db.close();
                    console.log('Metadata found: ', res);
                    resolve(res);
                }

              });
            }
        }); 
    });

}

我的程序阻塞的原因是什么?

(我尝试在外部(ws) =>之前添加异步,但结果是一样的)

【问题讨论】:

  • 对于初学者来说,if (err) throw err 是错误的,在你拥有它的两个地方都应该是 if (err) return reject(err);。为了将来参考,if (err) throw err 几乎永远不会出现在您的代码中。我从未遇到过正确错误处理的情况。然后你需要在你的await 周围加上一个try/catch,这样你就可以捕捉到任何可能发生的错误。错误处理在这里不容忽视,当事情没有按预期工作时,这可能是您应该首先查看的内容。
  • 另外,它应该是console.log('metadata:', blockchainMetadata);。您在日志语句中引用了错误的变量。
  • @jfriend00 Promise 自动将任何抛出的错误转换为可以在catch() 中捕获的被拒绝的 Promise。为什么throw 在这种情况下无效,这不只是性能问题,因为throw 周围没有优化吗?
  • @peteb - 该代码不在承诺回调中。它在数据库异步回调中。那里没有自动转换来拒绝。
  • 没有。 reject() 只是一个普通的函数调用。您的函数会继续执行块中的其余代码。您应该使用常规流控制将要在错误路径中执行的代码与非错误路径分开。常规 Javascript 编程技术。

标签: javascript node.js asynchronous promise async-await


【解决方案1】:

虽然 reject()'ing 是 promise 而不是 throw 为您解决了问题,但您的代码风格可以改进:

  • 将回调转换为 Promise 时,无需将函数声明为异步:它只会包装到另一个 Promise 中;
  • 声明函数可能比将函数表达式分配给 const 更好;
  • 为了减少缩进,模式将是 if (err) { return reject(err); }:这样就不需要 else 子句了;
  • 我们可能希望重用基于 Promise 的函数,因此提取通用逻辑会导致代码更具可读性;

OP 更多的是关于 Promise 而不是 async/await,所以这是一个重写的版本,具有更小的功能、浅缩进和使用更多的 async/await。

wss.on('connection', (ws) => {
  sendInitialState();
});

async function sendInitialState(ws) {
  console.log('Sending initial state!');
  const metadata = await getMetadata();
  console.log('metadata:', metadata);
}

function connect(url) {
  return new Promise((resolve, reject) => {
    MongoClient.connect(url, (err, db) => {
      if (err) {
        return reject(err);
      }
      resolve(db);
    });
  });
}

function findOne(db, collectionName, object) {
  return new Promise((resolve, reject) => {
    db.collection(collectionName).findOne(object, (err, res) => {
      if (err) {
        return reject(err);
      }
      console.log('Metadata found: ', res);
      resolve(res);
    });
  });
}

async function getMetadata() {
  const db = await connect(url);
  const res = await findOne(db, 'meta', {
    type: 'a'
  });
  db.close();
  console.log('Metadata found: ', res);
  return res;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多