【问题标题】:When using the await?何时使用等待?
【发布时间】:2018-07-31 17:38:02
【问题描述】:

我正在使用带有打字稿的续集。我知道代码是异步的,并且 在这里,我使用的是promise,并且代码有效..

我想知道什么时候必须使用 await 关键字?

const promises = []
let tabIdDoc = requestedListIdDoc.toString().split(",")

for (let thisIdDoc of tabIdDoc) {
    promises.push(sequelize.models['Document'].findById(thisIdDoc))
}

q.all(promises).then((resultReq) => {        
    const lstDocs = []
    for (let MyDoc of resultReq) {
        if (MyDoc.matriculeDoc != "") {
            lstDocs.push(sequelize.models['FolderDocContent'].findOrCreate({
                where: {                       
                }
            }))
        }
    }

    q.all(lstDocs).then(() => {
        return response.status(201)
    })           
}

这里需要 await 关键字吗?

【问题讨论】:

  • await 只能在 async 函数中使用。但是无论你可以用await 做什么,你都可以不用它(使用then 回调)。注意:return response.status(201) 在您的代码中毫无用处,除非您在 q.all(lstDocs) 之前放置 return

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


【解决方案1】:

您不必使用await,因为使用.then() 的其他编程总是可以完成工作,但有很多时候使用await 会使您的代码更简单。当您尝试对多个异步操作进行排序时尤其如此,当您需要在多个后续操作中使用先前的结果时更是如此。

示例 #1:在for 循环中序列化操作

假设你想把一堆item保存到你的数据库中,但是由于各种原因,你需要一个一个保存,并且需要按顺序保存(也就是说,你需要对它们进行排序):

async function saveItems(shoppingList) {
    for (let item of shoppingList) {
        // for loop will pause until this promise resolves
        await db.save(item);
    }
}

saveItems(myList).then(() => {
    // all done
}).catch(err => {
    // error here
});

如果不使用await,您将不得不使用更详细的设计模式,使用.reduce() 或者可能是您在完成先前操作时调用的递归函数。这是对循环的迭代进行排序的更简单的方法。

示例 #2:对函数中的不同操作进行排序

假设,您需要联系三个不同的外部服务。您需要从中获取一些数据,然后在进行第二次 API 调用时使用该数据,然后在第三次 API 调用中使用这两个数据:

const rp = require('request-promise');

async function getPrice(productName) {
     // look up productID
     const productID = await rp(`http://service1.com/api/getID?name=${productName}`);
     // use productID to lookup price
     const productPrice = await rp(`http://service1.com/api/getPrice?id=${productID}`);
     // put both productID and price into the shopping cart
     return rp({uri: 'http://service1.com/api/addToCart', body: {name: productName, id: productID}, json: true);
}

getPrice("Nikon_d750").then(total => {
    // all done here, total is new cart total
}).catch(err => {
    // error here
});

这两个示例都需要更多代码才能正确排序异步操作,并且您必须在 .then() 处理程序中嵌套逻辑跟随。使用 await 指示 JS 解释器自动为您执行嵌套。

其他一些例子here on MDN

await 需要牢记的几条规则:

  1. 您只能在以async 关键字为前缀的函数中使用它,如我上面的示例所示。

  2. 所有async 函数都返回一个承诺。如果你在函数中有一个显式的返回值,如return x,那么当所有异步操作完成时,该值将成为 promise 的解析值。否则,它只会返回一个具有 undefined 已解析值的承诺。因此,要使用来自async 函数的结果或知道它何时完成,您要么必须await 该函数的结果(在另一个async 函数内),要么必须在其上使用.then()

  3. await 仅在包含函数内暂停执行。就好像函数中的其余代码被放置在一个不可见的.then() 处理程序中,并且该函数在遇到第一个await 时仍将立即返回其承诺。它不会阻塞事件循环或阻塞async 函数之外的其他执行。这让很多人在第一次遇到await 时感到困惑。

  4. 如果你 await 拒绝的承诺,那么它 throws 你的函数中的一个异常。可以使用try/catch 捕获该异常。如果它没有被捕获,那么异步函数会自动捕获它并拒绝函数返回的承诺,其中抛出的值是拒绝原因。第一次使用await 很容易完全忘记您等待的承诺可能会拒绝的错误情况。

【讨论】:

  • 非常感谢您的回答,我明白了。但是,我正在使用箭头 typescript 函数,并且我正在尝试使用 asynch 关键字,但是我有这个错误:await 仅在 async 函数中有效
  • @AnaïsSaez 你也可以把async放在箭头函数前面
【解决方案2】:

您不一定必须使用await。但是,您应该在每个需要 then 的地方使用 await 以简化代码。

在你的例子中:

const promises = requestedListIdDoc.toString().split(",").map(thisIdDoc =>
    sequelize.models['Document'].findById(thisIdDoc)
);

const resultReq = await q.all(promises);
const lstDocs = resultReq.filter(myDoc => MyDoc.matriculeDoc != "").map(myDoc =>
    sequelize.models['FolderDocContent'].findOrCreate({
        where: {}
    })
);

await q.all(lstDocs);
return response.status(201)

【讨论】:

  • 谢谢你的例子!但是,我的 await 关键字有一个错误:“await 仅在异步函数中有效”
  • 把这段代码所在函数的function关键字改为async function
猜你喜欢
  • 2012-12-17
  • 2012-05-11
  • 2020-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多