关于承诺和需要异步/等待的澄清

时间:2020-06-28 16:44:20

标签: javascript node.js async-await

我一直在使用Promisesasync/await,它们几乎是同一件事吗?通常,我要做的就是兑现诺言并退还等。

function someFetchThatTakesTime(){
    // Promisify the request.
    return new Promise((resolve, reject) => {
        if(allGood){
            resolve();
        }else{
            reject();
    });
}

然后我可以做:

someFetchThatTakesTime()
    .then(console.log('all good.')
    .catch(console.log('some error occured.');

或者我可以做:

async function wrapMyFetch() {
    try {
        // Make the async call.
        data = await someFetchThatTakesTime();
        return data;
    } catch(err) {
        // Propagate the exception up stream.
        throw err;
    }
}

(async () => {
  let response = await wrapMyFetch();
  // Do stuff with the response.
})();

我想,到目前为止还很清楚。

但是,最近我遇到了这样的情况:我的应用程序不在乎等待获取结果和更新数据容器等。假设有一个更大的循环可以无限运行,并且任何Promised请求只会在应用程序运行时填补空白。

在那种情况下,我们真的不需要async/await模式对吗?我们只想继续前进,只要它们准备好就位(或者在发生错误的情况下不行),石头就会掉在我们身后。

我想澄清一下:async/await只会迫使事物线性运行,对吗?但是,如果我们不希望线性,并且可以接受生成的任务-Promises-在我们恢复运行周期的某个时间在后台完成其任务,则不需要{{ 1}}模式?正确吗?

2 个答案:

答案 0 :(得分:2)

我一直在使用Promises和async / await,它们几乎是同一回事吗?

嗯,async/await是基于promise建立的有用的语法。 Async/await依靠承诺才能工作。因此,我不太称呼它们相同,但是您可以使用awaittry/catch包围的.then().catch()来编写功能相同的代码。您可以使用。两种方法都依赖诺言。

但是,最近我遇到了这样的情况,我的应用程序不在乎等待获取结果和更新数据容器等。假设有一个更大的循环无限运行,并且所有承诺的请求都将被填充-在应用程序运行时填补空白。

在那种情况下,我们真的不需要异步/等待模式吗?我们只想继续前进,只要它们准备好就位,石头就会掉在我们后面。(如果发生错误,则不会)。

没有规则,呼叫者必须注意返回的诺言,或者必须等待其继续执行任务。因此,如果您想像您所说的那样“仅让石头掉入背景中”,而这对于您的应用程序来说是合适的,则可以采用这种方式进行编码。

这通常被称为“即发即弃”编码,您在其中开始一些异步操作,该操作将自行执行某些操作,并且您不需要注意何时完成或是否有错误,因为对调用代码没有影响。

但是,有一个规则,即您不能让承诺拒绝无法处理。因此,如果您要返回一个承诺,而调用方将不对其做任何事情,那么您必须确保所有拒绝都由操作本身(使用.catch())来处理,这样唯一的事情退还给您是一个坚定的承诺。即使您所做的只是注意到错误并且不采取任何措施,也必须抓住错误。

答案 1 :(得分:1)

async / await只会迫使事物线性运行,对吗?

不是全局的,不是。 awaitasync函数中创建代码,该代码用于等待传递给您的诺言付诸实施,但这只会影响您在其中使用的函数,而不会影响调用该函数的任何东西。

async函数是用于编写返回承诺的函数的语法糖。 await是用于兑现承诺的语法糖。它们在一起可以极大地简化使用Promise的方式(特别是通过使拒绝错误自动在调用树中传播)。

更具体地说,一个async函数同步运行其代码,直到第一个awaitreturn(或直到代码运行结束该函数的末尾)为止,此时它返回一个诺言。然后,它的逻辑等待诺言完成,然后继续下去。最终,它根据awaitreturn修改的最后一个承诺(或者如果代码执行结束时使用undefined履行的最后一个承诺)发生的承诺。

如果您不想等待诺言的兑现,则不必这样做,甚至不必使用async函数。只是不要在上面使用await。例如,假设我们有一个fetch的包装器,它可以为我们获取JSON(并修复了API脚枪):

async function fetchJSON(...args) {
    const response = await fetch(...args);
    if (!response.ok) {
        throw new Error("HTTP error " + response.status);
    }
    return response.json();
}

这里有一个async函数,使用它进行初始查询以获取要提取的事物的列表,然后并行获取所有这些事物::

async function fetchList(listUrl) {
    const list = await fetchJSON(listUrl);
    return Promise.all(list.map(item => fetchJSON(itemUrl)));
}

请注意,fetchList如何使用await来等待要提取的事物列表,但是却不等待这些事物;它只是从Promise.all返回其开始提取的项目列表的承诺。

还要注意await中的fetchJSON如何使fetchJSON的逻辑等待fetch的诺言得以解决,但没有除非呼叫者使用fetchJSON ,否则呼叫await的呼叫者会等待fetchListawait是第一个调用(获取列表),它不会等待列表中的项目。