首页 > 解决方案 > 承诺抛出错误,因为它无法访问它

问题描述

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

使用时ensureBufferingHasFinished().then(....).catch(err => console.log(err)),它告诉我无法访问条件this.serviceProvider

我以前使用过 Promise,但这是我第一次在这种特殊情况下使用 Promise。我怎样才能this.遵守承诺?非常感谢所有帮助!

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

标签: javascriptpromise

解决方案


对于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给您制作的 IIFE waitForBufferingComplete,尽管您的代码结构只有在支持 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 的平台进行开发,则该版本引入了箭头函数this,它们忽略执行上下文并保留其父级的词法范围:

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

阅读有关thisMDN的更多信息。


推荐阅读