当函数需要访问外部范围变量时,更好的方法来处理Promise流

时间:2018-01-04 01:47:11

标签: javascript node.js promise

我正在创建一个Node.js模块来与我的API进行交互,我使用superagent模块来执行请求。工作原理:

module.exports = data => {
  return getUploadUrl()
    .then(uploadFiles)
    .then(initializeSwam)

  function getUploadUrl() {
    const request = superagent.get(....)
    return request
  }

  function uploadFiles(responseFromGetUploadUrl) {
    const request = superagent.post(responseFromGetUploadUrl.body.url)
    // attach files that are in data.files
    return request
  }

  function initializeSwam(responseFromUploadFilesRequest) {
    // Same thing here. I need access data and repsonseFromUploadFilesRequest.body
  }
}

我觉得我做错了,但我无法以更好的方式思考,以达到同样的效果。

2 个答案:

答案 0 :(得分:6)

两种简单的方式:

  1. 编写您的函数以获取所需的所有参数

    const doStuff = data =>
      getUploadUrl()
      .then(uploadFiles)
      .then(initializeSwam)
    

    可能会成为

    const doStuff = data =>
      getUploadUrl()
        .then(parseResponseUrl) // (response) => response.body.url
        .then(url => uploadFiles(data, url))
        .then(parseResponseUrl) // same function as above
        .then(url => initializeSwam(data, url))
    
  2. 这应该可以正常工作(或者很好,取决于你在这些功能中正在做什么)。

    1. 部分应用您的功能

      const uploadFiles = (data) => (url) => {
        return doOtherStuff(url, data);
      };
      
      // same deal with the other
      const doStuff = data =>
        getUploadUrl()
          .then(parseResponseUrl)
          .then(uploadFiles(data)) // returns (url) => { ... }
          .then(parseResponseUrl)
          .then(initializeSwam(data));
      
    2. 所有这些技术(合理的时间和地点)的混合应足以满足您的许多需求。

答案 1 :(得分:1)

在上述代码段中构建代码的方式导致getUploadUrl()uploadFiles()initializeSwam()函数在最终.then(initializeSwam)调用之前未被声明。你在这个最后的.then()块中拥有的是三个函数声明,它只是在声明它们的命名空间中注册函数。 声明不会触发一个函数。

我相信你想要的是:

async function getUploadUrl() {             <-- notice the flow control for Promises
  const request = await superagent.get(....);
  return request;
}

async function uploadFiles(responseFromGetUploadUrl) {
  const request = await superagent.post(responseFromGetUploadUrl.body.url)
  // attach files that are in data.files
  return request;
}

async function initializeSwam(responseFromUploadFilesRequest) {
  // Same thing here. I need access data and 
  repsonseFromUploadFilesRequest.body
  const request = await ...;
}

module.exports = data => {
  return getUploadUrl(data)      <-- I'm guessing you wanted to pass this here
    .then(uploadFiles)
    .then(initializeSwam);
}

此方法使用ES6(或ES2015)的async/await功能;您也可以使用bluebird Promise库的 coroutines generator functions配对来实现相同的流量控制。