【问题标题】:Is there a way to know if a function is called inside a promise?有没有办法知道一个函数是否在一个 Promise 中被调用?
【发布时间】:2022-01-08 22:27:37
【问题描述】:

假设我有这段代码,并且我在一个包中编写了一个名为handleSmell() 的函数,其他人可以使用:

const streamSomeUrl = (url='https://salmon.net/river') => {

  console.info('...connecting...');
  const { data, headers } = await axios({
    url,
    method: 'GET',
    responseType: 'stream',
  });
  return new Promise((resolve, reject) => {
    data.on('data', (chunk) => {
       if(smellsFunny(chunk)) {
         // promise aware function
         handleSmell(chunk) // <--- behaves differently inside a promise. 
         // E.g. prints  "Smell inside a promise" 
       }
    });
  })
}

有没有办法让函数handleSmell 判断它是否在承诺中?我的意思是,它的行为与这里不同:

readFile('/etc/fish', (err, data) => {
  if(smellsFunny(data)) {
     // promise aware function
     handleSmell(data) // <--- behaves differently inside a promise.
     // E.g. prints  "Smell *not* inside a promise" 
     ...
     }
});

我试图弄清楚是否可以在不接受拒绝/解决回调的情况下处理 handleSmell 函数(然后如果丢失,知道我没有承诺)。

据我所知,我不能使用传递不同数据的事实,chunkdata 都是字符串/缓冲区?

这有可能吗?我受到这个question 的激励,主要来自一个答案:

任何时候你在一个 promise 回调中,你都可以使用 throw。但是,如果您在任何其他异步回调中,则必须使用拒绝。

new Promise(function() {
  setTimeout(function() {
    throw 'or nah';
    // return Promise.reject('or nah'); also won't work
  }, 1000);
}).catch(function(e) {
  console.log(e); // doesn't happen
});

我的偏好是抛出,但我想知道如果我调用拒绝回调(即来自父拒绝)它会起作用:


function handleSmell(suspectData, reject=False) {
  const inPromise = //?????
  if (inPromise && reject) {
    return reject('SMELLY REJECT!')
  } else if (inPromise) {
    throw new Error('SMELLY THROWN!')
  } else { console.error('SMELLY NON-PROMISE!') }
}
// Both these should work
new Promise(function() {
  setTimeout(function() {
    handleSmell('cheese');
}).catch(function(e) {
  console.log(e); // doesn't try to throw
});

new Promise(function(resolve, reject) {
  setTimeout(function() {
    handleSmell('cheese', reject);
  }, 1000);
}).catch(function(e) {
  console.log(e); // this works
});

另一种选择是承诺不承诺(根据链接)。

但如果可能的话,我可以避免吗?

【问题讨论】:

  • 请注意,您当然不能随便调用一个随机的 Promise.reject,您需要拒绝 您所在的 Promise
  • 我不明白为什么你需要一个新的 Promise 并且不要使用 axios 承诺。这是一个反模式
  • @jonrsharpe 我一定误解了我读到的答案之一的这一部分:setTimeout(function() { throw 'or nah'; // return Promise.reject('or nah'); also won't work }, 1000);
  • 您发布的内容说“也行不通”。因为它拒绝了一个 new 承诺,与外部承诺没有任何联系。
  • @GenericUser 这没有在浏览器中使用。我有 nodejs 因为我在 Node 中使用它,它是 ECMAScript 的服务器端表亲。我从一个确实有效的项目中获取了我的代码,但它基于此:futurestud.io/tutorials/…“本教程专门针对 Node.js,因为您会将图像流式传输到光盘上的文件。流式传输选项是'在浏览器中使用库时,Axios 支持。"

标签: javascript node.js promise


【解决方案1】:

这可能吗?

不,你不能那样做,不,你不应该那样做。函数的作用应该取决于它的参数,而不是从哪里调用它。

我受到这个问题的启发,主要来自答案:

任何时候你在一个 promise 回调中,你都可以使用 throw。 但是,如果您在任何其他异步回调中,则必须使用拒绝。

嗯,handleSmell 没有在回调中定义,它是一个独立的同步函数,所以它应该简单地抛出一个异常。

调用此类函数的正确方法是从 try 块内或从承诺 (then) 回调内。

new Promise((resolve, reject) => {
  setTimeout(() => {
    try {
      resolve(handleSmell('cheese'));
    } catch(err) {
      reject(err);
    }
  });
}).then(console.log, console.error);
new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('cheese');
  }, 1000);
}).then(handleSmell).then(console.log, console.error);
//      ^^^^^^^^^^^
// or .then(res => handleSmell(res)) for verbosity

【讨论】:

  • 所以没有办法防止它被调用,比如超时?
  • 不,没有办法做到这一点。而且它不在handleSmell 函数上:从setTimeout 异步回调中调用函数的程序员没有适当的错误处理是犯错的人,而不是编写handleSmell 的人.
  • 我希望在编写代码并将其发布到野外之前我可以做一些事情......
  • 如果你知道你的函数可能会像setTimeout那样在异步回调中被调用,并且人们会想要使用promise,你应该只做promisified 方法可用作您的库的一部分,因此他们不必自己做,也不会犯这个错误。但除此之外,您无需执行任何操作。
  • 现在是一个非常有用的想法。
猜你喜欢
  • 2019-01-04
  • 2019-11-17
  • 1970-01-01
  • 2021-08-15
  • 1970-01-01
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
  • 2014-02-22
相关资源
最近更新 更多