如何在承诺中平衡承诺?

时间:2017-05-18 17:34:34

标签: javascript promise

我有以下两个函数,每个函数都返回一个Promise:

const getToken = () => {
  return new Promise((resolve, reject) => {
    fs.readFile('token.txt', (err, data) => {
      if (err) { return reject(err) }
      if (!tokenIsExpired(data.token)) {
        return resolve(data.token)
      } else {
        return requestNewToken()
      }
    })
  })
}

const requestNewToken = () => {
  return new Promise((resolve, reject) => {
    restClient.get(url, (data, res) => {
      fs.writeFile('tokenfile.txt', data.token, err => {
        resolve(data.token)
      })
    })
  })
}

function1()
  .then(value => {
    console.log('taco')
  })
  .catch(err => {
    console.log(err)
  })

所以function1运行,并且(取决于某些条件),它有时返回function2,它返回另一个Promise。在此代码中,当调用function2时,console.log('taco')永远不会运行。为什么是这样?我认为如果你从Promise中返回一个Promise,嵌套Promise的解析值就是在顶级解析的。

为了让我能够使用它,我必须这样做:

const getToken = () => {
  return new Promise((resolve, reject) => {
    if (!tokenIsExpired()) {
      return resolve(getToken())
    } else {
      return requestNewToken ()
        .then(value => {
          resolve(value)
        })
    }
  })
}

这有效,但似乎我做错了什么。似乎应该有一种更优雅的方式来处理/构建它。

1 个答案:

答案 0 :(得分:1)

你认为promises是自动解包的,但在这种情况下,你从promise构造函数中返回,这被忽略,你需要调用resolve或{{1}而不是使用reject。我认为这可能是您正在寻找的解决方案:

return

在promise构造函数中,您需要调用const function1 = () => { return new Promise((resolve, reject) => { if (someCondition) { resolve('foobar') } else { resolve(function2()); } }) } resolve,这相当于在reject回调中使用returnthrow

如果您发现这种区别令人困惑(我这样做),您应该完全避免使用承诺构造函数,只需使用then开始一个新的链,如下所示:



Promise.resolve




使用更新的代码,我建议使用库来包装API,而不是自己访问promise构造函数。例如,使用bluebird' promisify

const function1 = () => {
  return Promise.resolve().then(() => {
    if (someCondition) {
      return 'foobar';
    } else {
      return function2();
    }
  })
}

const function2 = () => {
  return new Promise((resolve, reject) => {
    resolve('hello world')
  })
}
someCondition = false;
function1()
  .then(value => {
    console.log(value)
  })

我仍然忠实于您的源代码,但我注意到编写const bluebird = require('bluebird'); const readFile = bluebird.promisify(fs.readFile); const writeFile = bluebird.promisify(fs.writeFile); const getUrl = bluebird.promisify(restClient.get, {multiArgs:true}); const getToken = () => { return readFile('token.txt') .then((data) => { if(!tokenIsExpired(data.token)) { return data.token; } else { return requestNewToken(); } }); }; const requestNewToken = () => { return getUrl(url) .then(([data, res]) => { return writeFile('tokenFile.txt', data.token) .then(() => data.token); }); }; 可能存在错误,之后尝试阅读data.token属性那个文件。

为什么使用库而不是Promise构造函数?

  • 它允许您编写仅处理承诺的代码,(希望)更容易理解
  • 您可以确信回调API已正确转换而不会丢失错误。例如,如果您的token函数抛出错误,使用您的promise构造函数代码,它将丢失。您需要将所有内部回调代码包装在tokenIsExpired中,这很容易被遗忘。