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的调用都不会再次提示用户,然后退回一个拒绝