8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

为什么我在函数内部修改变量后它保持不变? - 异步代码参考

MP-SATARA 1月前

148 0

给出以下示例,为什么在所有情况下 outerScopeVar 都未定义?var outerScopeVar;var img = document.createElement('img');img.onload = function() { outerScopeVar = this.width;};...

给出以下例子,为什么 outerScopeVar 在所有情况下都是未定义的?

var outerScopeVar;

var img = document.createElement('img');
img.onload = function() {
    outerScopeVar = this.width;
};
img.src = 'lolcat.png';
alert(outerScopeVar);
var outerScopeVar;
setTimeout(function() {
    outerScopeVar = 'Hello Asynchronous World!';
}, 0);
alert(outerScopeVar);
// Example using some jQuery
var outerScopeVar;
$.post('loldog', function(response) {
    outerScopeVar = response;
});
alert(outerScopeVar);
// Node.js example
var outerScopeVar;
fs.readFile('./catdog.html', function(err, data) {
    outerScopeVar = data;
});
console.log(outerScopeVar);
// with promises
var outerScopeVar;
myPromise.then(function (response) {
    outerScopeVar = response;
});
console.log(outerScopeVar);
// with observables
var outerScopeVar;
myObservable.subscribe(function (value) {
    outerScopeVar = value;
});
console.log(outerScopeVar);
// geolocation API
var outerScopeVar;
navigator.geolocation.getCurrentPosition(function (pos) {
    outerScopeVar = pos;
});
console.log(outerScopeVar);

在所有这些示例中 undefined 都会输出 为什么 会发生这种情况。


注意: JavaScript 异步性 的典型问题 。欢迎改进此问题并添加更多社区可以识别的简化示例。

帖子版权声明 1、本帖标题:为什么我在函数内部修改变量后它保持不变? - 异步代码参考
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由MP-SATARA在本站《object》版块原创发布, 转载请注明出处!
最新回复 (0)
  • Fabrício 的回答非常正确;但我想用一些不太技术性的东西来补充他的回答,重点是通过类比来帮助解释异步性的概念


    打个比方……

    昨天,我工作中需要一位同事提供一些信息。我给他打了电话;以下是通话内容:

    :嗨,鲍勃,我想知道我们酒吧。吉姆想要一份报告,而你是唯一一个知道细节的人。

    鲍勃 :当然可以,但是要花大约 30 分钟的时间吧?

    :太好了,鲍勃。等你了解情况后再给我打电话吧!

    这时,我挂断了电话。由于我需要 Bob 提供的信息来完成我的报告,所以我放下报告去喝了杯咖啡,然后查看了一些电子邮件。40 分钟后(Bob 很慢),Bob 回电并给了我所需的信息。此时,我又继续写报告,因为我已经掌握了所需的所有信息。


    想象一下如果对话是这样的;

    :嗨,鲍勃,我想知道我们酒吧。吉姆想要一份报告,而你是唯一一个知道细节的人。

    鲍勃 :当然可以,但是要花大约 30 分钟的时间吧?

    :太好了,鲍勃。我会等的。

    我坐在那里等着。等了又等。等了 40 分钟。什么也没做,只是等待。最后,鲍勃给了我信息,我们挂了电话,我完成了报告。但我损失了 40 分钟的生产力。


    这是异步与同步行为

    这正是我们问题中所有示例中的情况。加载图像、从磁盘加载文件以及通过 AJAX 请求页面都是缓慢的操作(在现代计算环境中)。

    JavaScript 允许您注册一个回调函数,该函数将在慢速操作完成后执行, 而不是 等待 其他代码 使行为变得 异步 。如果 JavaScript 等待操作完成后再执行任何其他代码,这将是 同步 行为。

    var outerScopeVar;    
    var img = document.createElement('img');
    
    // Here we register the callback function.
    img.onload = function() {
        // Code within this function will be executed once the image has loaded.
        outerScopeVar = this.width;
    };
    
    // But, while the image is loading, JavaScript continues executing, and
    // processes the following lines of JavaScript.
    img.src = 'lolcat.png';
    alert(outerScopeVar);
    

    在上面的代码中,我们要求 JavaScript 加载 lolcat.png ,这是一个 很慢的 操作。回调函数将在这个缓慢的操作完成后执行,但与此同时,JavaScript 将继续处理下一行代码;即 alert(outerScopeVar) .

    这就是我们看到显示警报的原因 undefined ;因为是 alert() 立即处理的,而不是在图像加载之后处理的。

    为了修复我们的代码,我们要做的就是将<代码> alert(outerScopeVar) code。因此,我们不再需要将 outerScopeVar 变量声明为全局变量。

    var img = document.createElement('img');
    
    img.onload = function() {
        var localScopeVar = this.width;
        alert(localScopeVar);
    };
    
    img.src = 'lolcat.png';
    

    总是 看到回调被指定为一个函数,因为这是 JavaScript 中定义某些代码但稍后才执行的唯一方法。

    因此,在我们所有的示例中,都是 function() { /* Do something */ } 回调;要修复 所有 示例,我们所要做的就是将需要操作响应的代码移到那里!

    * Technically you can use eval() as well, but eval()对于此目的来说是邪恶的 for this purpose


    如何让呼叫者等待?

    您目前可能有一些类似于此的代码;

    function getWidthOfImage(src) {
        var outerScopeVar;
    
        var img = document.createElement('img');
        img.onload = function() {
            outerScopeVar = this.width;
        };
        img.src = src;
        return outerScopeVar;
    }
    
    var width = getWidthOfImage('lolcat.png');
    alert(width);
    

    但是,我们现在知道 会 return outerScopeVar 立即发生;在 onload 回调函数更新变量之前。这会导致 getWidthOfImage() 返回 undefined ,并 undefined 发出警报。

    为了解决这个问题,我们需要允许函数调用 getWidthOfImage() 注册一个回调,然后将宽度的警报移动到该回调内;

    function getWidthOfImage(src, cb) {     
        var img = document.createElement('img');
        img.onload = function() {
            cb(this.width);
        };
        img.src = src;
    }
    
    getWidthOfImage('lolcat.png', function (width) {
        alert(width);
    });
    

    ...和以前一样,请注意我们已经能够删除全局变量(在本例中 width )。

返回
作者最近主题: