【问题标题】:Correctly passing parameters to setTimeout正确地将参数传递给 setTimeout
【发布时间】:2025-12-22 20:35:13
【问题描述】:

我正在处理一个 Node.js 项目,但在使用 setTimeout 函数包装 Promise 函数时遇到问题。

我原来的Promise函数:

我想将此函数包装在对setTimeout() 的调用中,但在传递Promise 对象时遇到问题。我需要Promise 对象和setTimeout() 函数中可用的数据对象,但是当我将它们作为参数传递给setTimeout() 时,我仍然收到以下错误:

TypeError: 无法读取未定义的属性 'then'

我的代码:

return Promise.props(data).then(function (data) {
    data.companies = data.order && data.order.companies;
    if (!data.companies) {
        data.companies = {};
        data.companies[data.company.id] = data.company;
    }

    if (data.order) {
        if (data.order.contactentry) {
            data.order.pointofcontact = data.order.contactentry + ' ' + phone(data.order.contactentryphone);
        } else if (data.order.borrowername) {
            data.order.pointofcontact = data.order.borrowername + ' ' + phone(data.order.borrowerphone);
        } else if (data.order.lockboxcode) {
            data.order.pointofcontact = 'Lockbox ' + data.order.lockboxcode
        }
    }

    if (data.part && data.order && data.part.vendor) {
        var oid = data.order && data.order.id;
        var vid = data.part && data.part.vendor && data.part.vendor.id;
        if (!oid || !vid) {
            var e = new Error('Could not assemble vendor accept url, order id or part vendor id are missing')
            log.error({
                error: e,
                data,
            }, e.message);
            throw e;
        }
    }

    return data;
});

当作为参数传入时,数据对象在函数内部可用,但Promise 对象不可用。 如何正确传递Promise 对象以使其在setTimeout() 中可用?

【问题讨论】:

  • 为什么要用setTimeout 包裹Promise
  • 您在Promise 之前缺少new 关键字
  • @JosanIracheta - Promise.props 不需要 new :p - bluebirdjs.com/docs/api/promise.props.html
  • ugh @McWayWeb - 在使用 Promise 返回之前,您正在使用延迟等待异步代码完成?严重地?您确实意识到return Promise.props 返回的承诺不会在任何地方返回,对吗?不知何故,我认为您似乎认为您可以使用 Promises 使异步代码同步(提示:您不能)
  • 顺便说一句,您的“也尝试过”代码是将参数传递给 setTimeout 回调的正确方法 - 但使用此类代码无法解决您的整体问题

标签: javascript node.js promise settimeout


【解决方案1】:

你正在从里到外地接近这个。当您想将非 Promise 异步代码(例如 setTimeout)合并到基于 Promise 的代码中时,您应该隔离已包装的非 Promise 部分,而不是在其余的 Promise 代码中混得过深。

setTimeout 的承诺包装器:

function delay(ms) {
  return new Promise(function (resolve) {
    setTimeout(resolve, ms);
  });
}

然后就可以使用了:

return Promise.props(data)
    .then(function (result) {
      return delay(1000).return(result);
    });

由于您似乎在使用 Bluebird,您也可以跳过所有 setTimeout 内容并使用内置的 .delay 方法:

return Promise.props(data).delay(1000);

请注意,上述任何一项都会在解决data 中的所有承诺所需的时间上增加额外 1 秒的延迟。如果您的目标是使最短总时间为 1 秒,那么您可以使用我在 this question 中的方法:

return Promise.delay(1000).return(Promise.props(data));

【讨论】:

    【解决方案2】:

    我会忘记使用 setTimeout 的参数/返回值,而只使用 new Promise

    Promise.props 调用前的延迟:

    return new Promise(function (resolve) {
      window.setTimeout(function () {
        resolve(Promise.props(data));
      }, 1000);
    });
    

    或者,延迟 Promise.props 的结果:

    return Promise.props(data).then(function (data) {
      return new Promise(function (resolve) {
        window.setTimeout(function () {
          resolve(data);
        }, 1000);
      });
    });
    

    编辑:如果您使用的是 Bluebird,看起来他们内置了延迟运算符:

    【讨论】:

    • 请注意,当data 中的promise 之前已构建时,您不应延迟调用Promise.props。如果其中一个被拒绝,则会触发unhandledRejection 警告。