Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何修复承诺i̶;n̶̶;F̶;i̶;r̶;e̶;f̶;o̶;x̶;?_Javascript_Angularjs_Promise_Es6 Promise - Fatal编程技术网

Javascript 如何修复承诺i̶;n̶̶;F̶;i̶;r̶;e̶;f̶;o̶;x̶;?

Javascript 如何修复承诺i̶;n̶̶;F̶;i̶;r̶;e̶;f̶;o̶;x̶;?,javascript,angularjs,promise,es6-promise,Javascript,Angularjs,Promise,Es6 Promise,以下是我的承诺代码的简化示例: var sharedLocalStream = null; // ... function getVideoStream() { return new Promise(function(resolve, reject) { if (sharedLocalStream) { console.log('sharedLocalStream is defined'); resolve(sharedLocalStream); }

以下是我的承诺代码的简化示例:

var sharedLocalStream = null;
// ...
function getVideoStream() {
  return new Promise(function(resolve, reject) {
    if (sharedLocalStream) {
      console.log('sharedLocalStream is defined');
      resolve(sharedLocalStream);
    } else {
      console.log('sharedLocalStream is null, requesting it');
      navigator
          .mediaDevices
          .getUserMedia(constraints)
          .then(function(stream) {
            console.log('got local videostream', stream);
            sharedLocalStream = stream;
            resolve(sharedLocalStream);
          })
          .catch(reject);
    }
  });
}
我在几个地方异步使用这个函数。 这个问题与函数至少被调用两次有关,但在第二次调用中,承诺永远不会得到解决/拒绝。 这段代码在Chrome中运行得非常好。我还尝试使用$q服务,但也不起作用

我做错了什么,以及如何使这段代码工作

此外,我还想了很多方法来避免这种情况下的承诺,我别无选择,因为当用户确认麦克风和摄像头访问请求时,我不得不等待

更新:

var constraints = {
    audio: true,
    video: true
  };

如果调用两次
getVideoStream()
,则代码存在并发性问题。由于在第一次调用
sharedLocalStream
变量之前第二次调用
getVideoStream()
时没有强制排队或排序,因此很容易出现这样的情况:在
sharedLocalStream
有值之前,在两次调用开始之前创建两个流

这是代码设计的问题,而不是运行它的平台的问题。通常的解决方法是将第一个操作的承诺存储到共享变量中。然后测试一下,看看是否已经有了承诺。如果有,你只要回报你的承诺

如果缓存promise而不是流,则可以这样做:

var sharedLocalStreamPromise = null;
function getVideoStream() {
    // if we've already requested a local stream, 
    // return the promise who's fulfilled value is that stream
    if (!sharedLocalStreamPromise) {
        sharedLocalStreamPromise = navigator.mediaDevices.getUserMedia(constraints).catch(function(err) {
            // clear the promise so we don't cache a rejected promise
            sharedLocalStreamPromise = null;
            throw err;
        });
    }
    return sharedLocalStreamPromise;
}
第一个调用将把
sharedLocalStreamPromise
初始化为承诺。当第二个调用(或任何后续调用)传入时,它将返回相同的承诺


我正在考虑这个代码的一个边缘情况。如果承诺被拒绝,并且已经发生了对同一函数的第二次调用,那么它也将具有拒绝的承诺。

如果两次调用
getVideoStream()
,则代码存在并发性问题。由于在第一次调用
sharedLocalStream
变量之前第二次调用
getVideoStream()
时没有强制排队或排序,因此很容易出现这样的情况:在
sharedLocalStream
有值之前,在两次调用开始之前创建两个流

这是代码设计的问题,而不是运行它的平台的问题。通常的解决方法是将第一个操作的承诺存储到共享变量中。然后测试一下,看看是否已经有了承诺。如果有,你只要回报你的承诺

如果缓存promise而不是流,则可以这样做:

var sharedLocalStreamPromise = null;
function getVideoStream() {
    // if we've already requested a local stream, 
    // return the promise who's fulfilled value is that stream
    if (!sharedLocalStreamPromise) {
        sharedLocalStreamPromise = navigator.mediaDevices.getUserMedia(constraints).catch(function(err) {
            // clear the promise so we don't cache a rejected promise
            sharedLocalStreamPromise = null;
            throw err;
        });
    }
    return sharedLocalStreamPromise;
}
第一个调用将把
sharedLocalStreamPromise
初始化为承诺。当第二个调用(或任何后续调用)传入时,它将返回相同的承诺

我正在考虑这个代码的一个边缘情况。如果承诺被拒绝并且已经发生了对同一函数的第二次调用,那么它也将具有拒绝的承诺。

没有IIFE

let sharedLocalStreamPromise;

function getVideoStream() {
    return sharedLocalStreamPromise = sharedLocalStreamPromise || navigator.mediaDevices.getUserMedia(constraints);
};
有生之年

const getVideoStream = (() => {
    let sharedLocalStreamPromise;
    return () => sharedLocalStreamPromise = sharedLocalStreamPromise || navigator.mediaDevices.getUserMedia(constraints);
})();
交替地

var getVideoStream = () => {
    const result = navigator.mediaDevices.getUserMedia(constraints);
    getVideoStream = () => result;
    return getVideoStream();
};
最后一个函数在第一次调用时创建一个
结果
(由getUserMedia返回的承诺),然后覆盖自身以仅返回该结果。。。在随后调用
getVideoStream
时没有条件-因此,理论上“更快”(在本例中,速度是一个没有意义的点)

没有iLife

let sharedLocalStreamPromise;

function getVideoStream() {
    return sharedLocalStreamPromise = sharedLocalStreamPromise || navigator.mediaDevices.getUserMedia(constraints);
};
有生之年

const getVideoStream = (() => {
    let sharedLocalStreamPromise;
    return () => sharedLocalStreamPromise = sharedLocalStreamPromise || navigator.mediaDevices.getUserMedia(constraints);
})();
交替地

var getVideoStream = () => {
    const result = navigator.mediaDevices.getUserMedia(constraints);
    getVideoStream = () => result;
    return getVideoStream();
};

最后一个函数在第一次调用时创建一个
结果
(由getUserMedia返回的承诺),然后覆盖自身以仅返回该结果。。。在随后调用
getVideoStream
时没有任何条件-因此,理论上“更快”(在本例中,速度是一个没有意义的问题)

这是一个问题,因为您正在将现有承诺包装到另一个承诺中,而不仅仅是返回您已经拥有的承诺。在你的
if()
中,你可以只做
返回承诺。解决(sharedLocalStream)
,而在你的
中,你可以只返回你已经做出的承诺,而不创建新的承诺。firefox中的承诺不会被破坏-问题在于我们不清楚你到底有什么问题,但我相当怀疑Firefox中的承诺是否有问题。更可能的问题是您的代码如何使用承诺,或者您调用的某个函数在两次调用时如何响应。@jfriend00您能详细说明一下吗?我刚刚读过这篇文章,但正如您可能看到的,我的代码需要对刚获得的流进行一些处理。@jfriend00-请看,这是一个问题,因为您正在将一个现有的承诺包装到另一个承诺中,而不仅仅是返回您已有的承诺。在你的
if()
中,你可以只做
返回承诺。解决(sharedLocalStream)
,而在你的
中,你可以只返回你已经做出的承诺,而不创建新的承诺。firefox中的承诺不会被破坏-问题在于我们不清楚你到底有什么问题,但我相当怀疑Firefox中的承诺是否有问题。更可能的问题是您的代码如何使用承诺,或者您调用的某个函数在两次调用时如何响应。@jfriend00您能详细说明一下吗?我刚刚读了这篇文章,但正如您可能看到的,我的代码需要对刚获得的流进行一些处理。@jfriend00-查看INSTEAD看起来我必须实现排队,并等待用户确认请求。有什么好办法吗?我喜欢你的解决方案,我本来想存储承诺,但最终存储了一个流,这是个坏主意。
清除承诺,这样我们就不会缓存被拒绝的承诺。
在这种情况下,这是没有意义的,因为一旦用户拒绝getUserMedia,所有后续对getUserMedia的调用都不会再次提示用户,然后退回一个拒绝