从复杂函数返回字符串

时间:2018-03-29 16:09:16

标签: javascript audio return blob

Javascript问题:如何从此处显示的功能返回我想要的网址:

function getAudioBlob() {
 return recorder && recorder.exportWAV(function (blob) {
   var url = URL.createObjectURL(blob);
   console.log(url) // works great!
   return url;
 }, ("audio/mp3"));
}

console.log(getAudioBlob()); // the log reads 'undefined'

我无法获取此功能返回的URL字符串(用于音频blob)。我的目标是能够使用Blob Url将音频录制内容上传到服务器。

我的问题源于这样一个事实,即我不知道如何捕捉从这种尴尬的安排中返回的值:

recorder && recorder.exportWAV(function (blob) {...

我放了一个'返回'在它面前,但显然不起作用。我该如何重写它呢?谢谢!

1 个答案:

答案 0 :(得分:4)

exportWAV是异步的,因此它会在您的函数执行后完成。您可以使用回调或Promise准备好运行某些代码。例如:

function getAudioBlob(recorder) {
  return new Promise((resolve) => {
    recorder.exportWAV((blob) => {
      const url = URL.createObjectURL(blob);
      resolve(url);
    }, 'audio/mp3');
  });
}

// Use the function..
if (recorder) {
  getAudioBlob(recorder).then(url => console.log('blob url:', url));
}

当你完成网址后,你应该拨打URL.revokeObjectURL(url)来释放内存。

我关心你的意思"我的目标是能够使用Blob Url将音频录制内容上传到服务器。"您创建的URL仅适用于该客户端,仅在该选项卡打开时存在。

以下是您的问题的一些PoC代码:

// This is a shorthand for writing a function that returns something.
const getAudioBlob = recorder =>
  new Promise(resolve => recorder.exportWAV(resolve, 'audio/mp3'));

function uploadBlobToServer(blob) {
  const fd = new FormData();
  fd.append('recording', blob, 'recording.mp3');
  return fetch('/api/recording/upload', { method: 'POST', body: fd });
}

function stopRecording() {
  if (!recorder) {
    console.error('No recorder found');
    return;
  }

  recorder.stop();
  getAudioBlob(recorder).then((blob) => {
    // Not sure what this is but guessing it needs to be called
    // AFTER exportWAV has finished?
    recorder.clear();

    // When we return a Promise inside another, the subsequent .then()/.catch()
    // Will have the result of this promise (in this case the result of the upload).
    return uploadBlobToServer(blob);
  })
    .then((res) => {
      if (res.status > 400) {
        throw new Error(res.statusText);
      }
    })
    .then((res) => {
      console.log('Recording uploaded to server successfully.', res.status, res.statusText);
    })
    .catch((error) => {
      console.error('Failed to upload recording to server.', error);
    });
}

// Or this is how you could write that function using asyc/await which is a bit cleaner
// than using the Promises directly, but it's only supported by new browser versions.
async function stopRecording() {
  if (!recorder) {
    console.error('No recorder found');
    return;
  }

  recorder.stop();

  try {
    const blob = await getAudioBlob(recorder);
    const res = await uploadBlobToServer(blob);

    // The HTTP Status code from the server was an error.
    if (res.status > 400) {
      throw new Error(res.statusText);
    }

    console.log('Recording uploaded to server successfully.', res.status, res.statusText);

    recorder.clear();
  } catch (error) {
    console.error('Failed to create and upload your recording:', error);
  }
}