javascript - “return deferred.promise(this)”返回未定义

标签 javascript jquery jquery-deferred

如果我使用以下超时解决3秒后的延迟,以下代码将起作用:

    var myConstructor = function(){
        var deferred = $.Deferred();
        this.message = "yo";
        setTimeout(function(){
            deferred.resolve();
            }, 3000);
        return deferred.promise(this);
    }
    var myObj = new myConstructor().done(function(){
        console.log(myObj.message);
    })


但是如果我立即解决延期而没有超时,如下所示...

    var myConstructor = function(){
        var deferred = $.Deferred();
        this.message = "yo";
        deferred.resolve();
        return deferred.promise(this);
    }
    var myObj = new myConstructor().done(function(){
        console.log(myObj.message);
    })


...然后我得到以下错误:console.log行上的“无法读取未定义的属性'消息'”。为什么立即解决延迟问题会导致myObj不确定?

编辑:

在我回顾@ T.J。 Crowder给出了一个令人惊奇的答案,很明显,这就是我需要对代码进行的更改:

    var myConstructor = function(){
        var deferred = $.Deferred();
        this.message = "yo";
        deferred.resolve();
        return deferred.promise(this);
    }
    var myObj = new myConstructor();

    myObj.done(function(){
        console.log(myObj.message);
    })

最佳答案

但是如果我立即解决延期而没有超时,如下所示...


在已解决的done上调用Deferred时,它将同步调用其回调。在您的情况下,这意味着在分配操作完成之前调用了回调,因此myObj没有值(尚未)。

让我们打破这段代码:

var myObj = new myConstructor().done(function(){
    console.log(myObj.message);
});


...变成什么时候发生(当您不使用setTimeout时):


进入作用域后(在按照逐步的顺序执行该代码行之前),将创建一个名为myObj的变量,其值为undefined
评估new myConstructor(),其中:

创建一个由myConstructor.prototype支持的新空白对象
调用myConstructor,其中this引用该对象

匿名函数已创建(但未执行)。
done被调用,传入匿名函数。

因为Deferred已经解决,所以done立即调用回调而不是等待。 (我碰巧是一群不同意这种设计选择的人*,但这就是jQuery的promise / deferreds设计。)
回调访问值为myObjundefined,因此引发异常

done返回,并且myObj获取其返回值。


但是,当您使用setTimeout时:


进入作用域后(在按照逐步的顺序执行该代码行之前),将创建一个名为myObj的变量,其值为undefined
评估new myConstructor(),其中:

创建一个由myConstructor.prototype支持的新空白对象
调用myConstructor,其中this引用该对象
创建计时器回调,但尚未执行

匿名函数已创建(但未执行)。
done被调用,传入匿名函数。由于Deferred尚未解决,因此不会调用回调。
done返回,并且myObj获取其返回值。
一段时间后,计时器启动,并解析Deferred

回调被调用。
回调访问myObj,它具有步骤5中的值并成功使用它。





*“设计选择”-如果done已解析,则让Deferred同步调用回调是一种设计选择。它权衡了语义和性能。基本上,jQuery开发人员有两种选择:


同步调用回调,这意味着语义是混乱的(有时被同步调用,有时被异步调用),或者
即使状态已经知道(通过setTimeout(..., 0)或类似方式)也异步调用回调,这意味着保留语义(回调始终是异步的),但是性能可能会受到影响(浏览器有时会在setTimeout上施加至少4ms的延迟)回调,尽管不如HTML5规范中要求的那样一致)。


哪个是对的?这完全是一个见解。从主观上来说,对我而言,语义应该胜出:可能是异步的回调应该始终是异步的-如果他们做出了这样的选择,您的代码就不会遇到问题,因为回调总是在赋值之后发生至myObj完成。但是聪明的jQuery开发人员做出了另一种选择,这是他们的正确选择。 :-)

关于javascript - “return deferred.promise(this)”返回未定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26026506/

相关文章:

javascript - JSON 数据到 JavaScript 数组

javascript - 有没有办法可以在 Testcafe 中输出每个测试的持续时间?

javascript - 通知我网站的 Android 用户从网站安装 Android 应用程序?

javascript - Highcharts 的 json 数据映射问题

Jquery Datatable 将一行从一个表拖放到另一个表

javascript - jQuery 在不同大小的容器中居中多个动态图像

jquery - polymer ! Ajax中调用函数成功

javascript - 使用 Jquery $When 进行异步和同步函数调用

jquery - 如何使所有 AJAX 调用按顺序进行?

jquery - 从同一函数返回两个 ajax 调用 - $(when) 这是执行的吗?