承诺抛出错误,因为它无法访问此错误

时间:2018-08-06 16:30:43

标签: javascript promise

我有一段代码,该代码使用promises API检查serviceProvider组件中的缓冲功能是否已完成。 serviceProvider带有一个标志,可以用getBufferingStatus()进行轮询。

使用ensureBufferingHasFinished().then(....).catch(err => console.log(err))时,显示无法从this.serviceProvider访问该条件

我以前曾经使用诺言,但这是我在这种特殊情况下第一次使用诺言。如何将this.绑定到诺言?感谢所有帮助!

ensureBufferingHasFinished() {
  return new Promise(function (resolve, reject) {
    (function waitForBufferingComplete(){
        if (!this.serviceProvider.getBufferingStatus()) {
          alert("RESOLVED");
          return resolve();
        }
        setTimeout(waitForBufferingComplete, 250);
    })();
  });
}

5 个答案:

答案 0 :(得分:2)

this关键字让不熟悉JavaScript如何分配其值的细微差别的人感到头疼。 this的值对应于执行上下文,而不是范围。在这种情况下,waitForBufferingComplete的执行上下文与调用ensureBufferingHasFinished的上下文不同。

关于如何确保访问所需内容,您有一些选择。

将变量分配给外部作用域

在您的函数相互嵌套的情况下,分配this或其属性的古老做法是快速而可靠的:

function ensureBufferingHasFinished() {
    var that = this,
        sp = this.serviceProvider;
    return new Promise(function (resolve, reject) {
        (function waitForBufferingComplete() {
            //you can use "that.serviceProvider", or "sp"
            if (!sp.getBufferingStatus()) {
                alert("RESOLVED");
                return resolve();
            }
            setTimeout(waitForBufferingComplete, 250);
        })();
    });
}

使用function.bind()

在函数上调用bind会强制它具有您显式给出的执行上下文作为其参数,如果您在包含所需值的范围内不进行回调或无法进行回调,则将更为有用。

function ensureBufferingHasFinished() {
    return new Promise(function (resolve, reject) {
        (function waitForBufferingComplete() {
            if (!this.serviceProvider.getBufferingStatus()) {
                alert("RESOLVED");
                return resolve();
            }
            setTimeout(waitForBufferingComplete.bind(this), 250);
        }.bind(this))();
    }.bind(this));
}

function ensureBufferingHasFinished() {
    return new Promise(_resolveBufferingPromise.bind(this));
}

function _resolveBufferingPromise(resolve, reject) {
    (function waitForBufferingComplete() {
        if (!this.serviceProvider.getBufferingStatus()) {
            alert("RESOLVED");
            return resolve();
        }
        setTimeout(waitForBufferingComplete.bind(this), 250);
    }.bind(this))();
}

您也可以将serviceProvider传递给您在waitForBufferingComplete周围创建的IIFE,尽管您的代码结构只有在支持与ES5兼容的浏览器setTimeout时才应该这样做。在此之前不支持传递其他参数:

function ensureBufferingHasFinished() {
    return new Promise(function (resolve, reject) {
        (function waitForBufferingComplete(serviceProvider) {
            if (!serviceProvider.getBufferingStatus()) {
                alert("RESOLVED");
                return resolve();
            }
            setTimeout(waitForBufferingComplete, 250, serviceProvider);
        })(this.serviceProvider);
    }.bind(this));
}

使用箭头功能(ES2015或更高版本)

如果您正在开发支持ES2015的平台,则该版本引入了arrow functions,它忽略了执行上下文并保留了其父级this的词汇范围:

function ensureBufferingHasFinished() {
    return new Promise((resolve, reject) => {
        var waitForBufferingComplete = () => {
            if (!this.serviceProvider.getBufferingStatus()) {
                alert("RESOLVED");
                return resolve();
            }
            setTimeout(waitForBufferingComplete, 250);
        }
    });
}

Read up on more about this on MDN

答案 1 :(得分:1)

您可以做的是在sureBufferingHasFinished的参数中传递serviceProvider实例。

n1

答案 2 :(得分:1)

this绑定到Promise函数,并将serviceProvider作为参数传递给iife。将serviceProvider作为第三个参数传递到setTimeout

ensureBufferingHasFinished() {
  return new Promise(function (resolve, reject) {
    (function waitForBufferingComplete(serviceProvider){
        if (!serviceProvider.getBufferingStatus()) {
          alert("RESOLVED");
          return resolve();
        }
        setTimeout(waitForBufferingComplete, 250, serviceProvider);
    })(this.serviceProvider);
  }.bind(this));
}

答案 3 :(得分:1)

您的this指向函数的内部范围。您可以使用局部变量来存储this的引用,并在所有内部范围中使用它:

ensureBufferingHasFinished() {
let ref = this;
return new Promise(function (resolve, reject) {
    (function waitForBufferingComplete(){
        if (!ref.serviceProvider.getBufferingStatus()) {
          alert("RESOLVED");
          return resolve();
        }
        setTimeout(waitForBufferingComplete, 250);
    })();
  });
}

答案 4 :(得分:-1)

尝试一下:

    waitForBufferingComplete = function(bufferingSuccess){
            if (!this.serviceProvider.getBufferingStatus()) {
                  bufferingSuccess(true);
            }
            else{
                setTimeout(waitForBufferingComplete, 250);
            }
        }

        ensureBufferingHasFinished() {
          return new Promise(function (resolve, reject) {
            waitForBufferingComplete(function(isFinishedBuffering){
                if (isFinishedBuffering){
                    resolve('ok');
                }                    
            });
          });
        }