等待从父函数解决的承诺

Posted

技术标签:

【中文标题】等待从父函数解决的承诺【英文标题】:Waiting for promise to resolve from parent function 【发布时间】:2019-10-23 01:18:08 【问题描述】:

我的节点应用程序中有一个主线程,例如:

function main_thread() 
  console.log("Starting");
  values = get_values(1);
  console.log(values);
  console.log("I expect to be after the values");

get_values 函数使用node_redis 包调用hgetall 函数。该函数提供回调,但可以被承诺:

function get_values(customer_id) 
  // Uses a callback for result
  new Promise(function(resolve, reject) 
    redis_client.hgetall(customer_id, function (err, result) 
    if (err) console.log(err)
      console.log("About to resolve");
      resolve(result);
    );
  )
  .then((result) => 
    console.log(result);
  );

这对于函数内的 Promise 链接非常有用,但在我的主线程中效果不佳,因为我迫不及待地返回值。

以下是我在我使用的主要语言 ruby​​ 中的操作方式:

def get_values(customer_id)
  return @redis_client.hgetall(customer_id)
end

如何在可重用函数中创建一个 Promise 并让主线程等待该函数从该 Promise 返回响应?

编辑:

有人建议可以在主线程中链接then 来返回承诺。但是,这仍然意味着在函数调用之后在then 块之前执行之后的主线程中的任何代码。

编辑 2:

经过与一些 IRL JS 开发者朋友的长时间讨论,尝试创建同步脚本似乎违反了现代 JS 的精神。我将回到我的应用程序设计并努力使其异步。

【问题讨论】:

再次出现同样的问题,没有返回承诺。 Promise returns with 'undefined' or babel compiled code doesn't wait for return (async/await) 您的主线程永远不会等待异步操作完成。单个函数可以使用await 等待,但该函数仍会立即返回一个承诺并且主线程继续。 javascript 的主线程从不等待异步操作。请参阅其他答案以了解如何正确使用 Promise,但不要认为其中任何一个都会“暂停”整个主线程。不会的。 不能让主线程等待。您需要 return 来自 get_values 的承诺,然后在 main_thread 函数中使用承诺链接(或 await)。 【参考方案1】:

这是一个使用 async/await 的工作示例。我已经用超时和数据数组替换了 redis。

async function main_thread() 
  console.log("Starting");
  values = await get_values(1);
  console.log(`After await: $values`);
  console.log("I expect to be after the values");


async function get_values(customer_id) 
  return new Promise((resolve, reject) => 
      setTimeout(() => 
        const result = [1, 2, 3];
        console.log(`Resolving: $result`);
        resolve(result);
      , 300);
  );


main_thread();

进一步阅读:

Using Promises Promise Constructor

【讨论】:

谢谢@crashmstr。这绝对是做我想做的事的方法!然而,在与一些我知道 IRL 的 JS 开发人员讨论之后,这种行为似乎与现代 JS 编程有悖常理。我想我将在我的应用程序中进行一些设计更改并将其构建为更加异步。这绝对是问题的答案!【参考方案2】:

get_values中返回承诺

function get_values(customer_id) 
  // Uses a callback for result
  return new Promise(function(resolve, reject) 
    redis_client.hgetall(customer_id, function (err, result) 
    if (err) console.log(err)
      console.log("About to resolve");
      resolve(result);
    );
  )
  .then((result) => 
   reject(result);
  );

现在在你的主线程中,你可以像这样等待它:

function main_thread() 
  console.log("Starting");
  get_values(1).then(function(values) 
    console.log(values);
  ).catch(function(error) 
    console.error(error);
  );

【讨论】:

谢谢普瑞克。除了如果我在 get_values() 函数之后有代码,那么该代码将在 then 之前运行,对吗?我希望暂停这个主线程来执行此操作。 在这种情况下,您可以将该代码添加到 then 块中。【参考方案3】:

就像从你的函数中返回承诺(链)一样简单

function get_values(customer_id) 
  // Uses a callback for result
  return new Promise(function(resolve, reject) 
    redis_client.hgetall(customer_id, function (err, result) 
    if (err) console.log(err)
      console.log("About to resolve");
      resolve(result);
    );
  )
  .then((result) => 
    console.log(result);
  );

然后在你的主要async functionfunction

let result = await get_values();get_values.then(function(result))

function main_thread() 
  console.log("Starting");
  values = get_values(1).then(function(values)
    console.log(values);
    console.log("I expect to be after the values");
  );


async function main_thread() 
  console.log("Starting");
  let values = await get_values(1);
  console.log(values);
  console.log("I expect to be after the values");

【讨论】:

注意:thread 在这里可能用词不当 --- 除非线程是从 web worker 调用的,或者由于某种原因在单独的节点进程上调用。 感谢科迪的快速回复!但这似乎不会让数据回到主线程?然后封装在then函数中,主线程继续后数据还在使用,对吧? 最后那是一种伪代码,我已经更新它以使其更清晰。 您必须将其余代码放在get_values.then() 中——是的,这会变得丑陋且嵌套很快,因此请使用async function main_thread() 并使用await foo() 来避免这种嵌套。

以上是关于等待从父函数解决的承诺的主要内容,如果未能解决你的问题,请参考以下文章

打字稿 - 在函数返回之前等待承诺解决

承诺等待得到解决而不返回

在等待时,未能同时解决的发电机产生的承诺

等待所有承诺解决

等待/异步如何处理未解决的承诺

等待但从未解决/拒绝承诺内存使用[重复]