在返回函数的变量之前,如何等待 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 完成?的主要内容,如果未能解决你的问题,请参考以下文章
Angular 8 - 如何使用 Promises 和 Async/Await [重复]