在返回函数的变量之前,如何等待 promise 完成?

Posted

技术标签:

【中文标题】在返回函数的变量之前,如何等待 promise 完成?【英文标题】:How do I wait for a promise to finish before returning the variable of a function? 【发布时间】:2015-03-01 19:32:12 【问题描述】:

我仍在努力兑现承诺,但感谢这里的社区。​​p>

我有一个查询 Parse 数据库的简单 JS 函数。它应该返回结果数组,但显然由于查询的异步性质(因此是承诺),函数在结果之前返回,给我留下一个未定义的数组。

我需要做什么才能让这个函数等待 promise 的结果?

这是我的代码:

function resultsByName(name)
   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    var promise = query.find(
               success: function(results) 
               // results is an array of Parse.Object.
                             console.log(results);
                             //resultsArray = results;
                             return results;
               ,

               error: function(error) 
               // error is an instance of Parse.Error.
                             console.log("Error");
               
    );                           


【问题讨论】:

你也可以考虑使用 async/await。从 7.6 版开始,Node 现在支持开箱即用的 async/await 【参考方案1】:

我需要做什么才能让这个函数等待 promise 的结果?

使用async/await(不是ECMA6的一部分,但是 自 2017 年底起可用于 Chrome、Edge、Firefox 和 Safari,请参阅 canIuse) MDN

    async function waitForPromise() 
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    

由于评论而添加: 异步函数总是返回一个 Promise,在 TypeScript 中它看起来像:

    async function waitForPromise(): Promise<string> 
        // let result = await any Promise, like:
        let result = await Promise.resolve('this is a sample promise');
    

【讨论】:

如果在没有等待的情况下调用(或在非异步代码中),异步函数仍将返回一个 Promise 对象。如果不确定,请检查 console.log(waitForPromise()) 的结果。检查异步函数中的 console.log(result) 打印出您期望的结果,但是异步函数的返回立即发生而不会阻塞并返回一个承诺。 javascript 中的阻塞通常是非常糟糕的,因为它是一个单线程应用程序,阻塞会使任何其他发布/订阅客户端的通知饿死,实际上会使整个应用程序陷入瘫痪。 .net 在类似任务类的“承诺”上有 .wait()。 Javascript 是否缺少此功能?在退出我的节点命令行工具之前,我需要等待一些东西,该工具可能会将其输出传递到另一个工具。 "await" 仅在异步函数中有效。这意味着它在承诺范围之外不起作用。 @SRM 我觉得你的评论是基于对样本的误解——它是关于“内部” Promise.resolve (作为最简单的 Promise 示例),所以没有像你这样的外部调用者在您的评论中说明。所以我决定更新答案。 @TamusJRoyce Guess 这本身就是一个问题,但我认为在 C# 中您可以使用 Task.ContinueWith(Task),这与您在接受的答案中看到的想法相同(称为“那么()”)。 我想我现在明白了。我几乎可以将整个脚本包装在一个巨大的异步函数中。并将该函数称为我脚本的最后一行。该功能仍然是一个样板。但比我之前想象的要少得多。我不习惯在函数中编写函数。谢谢@MartinMeeser!【参考方案2】:

您不想让函数等待,因为 JavaScript 旨在实现非阻塞。 而是在函数结束时返回 Promise,然后调用函数可以使用 Promise 来获取服务器响应。

var promise = query.find(); 
return promise; 

//Or return query.find(); 

【讨论】:

你的所有带有success: 位的回调都关闭了。 或者更好:return query.find();. 也可以。出于说明目的,我将保留它,但将其添加为评论。 我试过这个,但结果似乎是不确定的。 resultsByName("name").then(function(results) console.log("得到数组 "+results.count); ); 谢谢,结果函数中一定有某种错误。它现在正在工作。我将 console.log 更改为 results.length,可以看到我返回的数组中有 1 个条目:)【参考方案3】:

您实际上并没有在这里使用 Promise。 Parse 允许您使用回调或承诺;你的选择。

要使用承诺,请执行以下操作:

query.find().then(function() 
    console.log("success!");
, function() 
    console.log("error");
);

现在,要在 Promise 完成后执行某些内容,您可以在 then() 调用中的 Promise 回调中执行它。到目前为止,这与常规回调完全相同。

真正充分利用 Promise 的方法是链接它们,如下所示:

query.find().then(function() 
    console.log("success!");

    return new Parse.Query(Obj).get("sOmE_oBjEcT");
, function() 
    console.log("error");
).then(function() 
    console.log("success on second callback!");
, function() 
    console.log("error on second callback");
);

【讨论】:

结果对象是什么类型的对象?因为它似乎不包含我的数组 应该是Parse.Object的数组。【参考方案4】:

不是返回resultsArray,而是返回一个结果数组的promise,然后在调用站点上返回then——这有一个额外的好处,即调用者知道函数正在执行异步I/O。 JavaScript 中的并发编码就是基于此——您可能想阅读this question 以获得更广泛的想法:

function resultsByName(name)
   
    var Card = Parse.Object.extend("Card");
    var query = new Parse.Query(Card);
    query.equalTo("name", name.toString());

    var resultsArray = [];

    return query.find();                           



// later
resultsByName("Some Name").then(function(results)
    // access results here by chaining to the returned promise
);

您可以在 Parse's own blog post about it 中查看更多使用 parse promise 和查询的示例。

【讨论】:

你能告诉我这个有什么支持吗? IE9 支持吗? 是的,但是 Parse 本身基本上已经死了,所以@SandrinaPereira。这是解析 cloud 代码。 啊,所以这不仅仅是纯javascript?我正在寻找一种方法来做到这一点(等待一个函数完成以启动另一个),但只能使用纯 javascript.. 问题是关于解析代码,而不是承诺。 Promise 可以在任何浏览器中工作(使用库)。 Bluebird 在 IE6 和 netscape 7 中运行。 我已经读了两天了,但仍然没有人解决这个问题。这个公认的答案与其他答案相同。该函数返回一个 Promise,而不是 OP 请求的值。为什么这个答案被标记为接受?

以上是关于在返回函数的变量之前,如何等待 promise 完成?的主要内容,如果未能解决你的问题,请参考以下文章

如何在做其他事情之前返回许多 Promise 并等待它们

Angular 8 - 如何使用 Promises 和 Async/Await [重复]

Promise mysql返回未定义,如何让函数等待结果

js Promise 等待多个异步操作执行完再去做一些操作

返回一个promise而不等待nodejs中函数中的依赖promise

让 promise 在返回前等待几秒钟