给出以下示例,为什么在所有情况下 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 异步性 的典型问题 。欢迎改进此问题并添加更多社区可以识别的简化示例。
对于那些寻求快速参考以及使用承诺和异步/等待的一些示例的人来说,这是一个更简洁的答案。
从简单的方法(不起作用)开始,该方法调用异步方法(在本例中 setTimeout
)并返回一条消息:
function getMessage() {
var outerScopeVar;
setTimeout(function() {
outerScopeVar = 'Hello asynchronous world!';
}, 0);
return outerScopeVar;
}
console.log(getMessage());
undefined
在这种情况下被记录,因为 getMessage
之前返回 setTimeout
并更新 outerScopeVar
.
解决这个问题的两种主要方法是使用 回调 和 承诺 :
回调
这里的变化是 getMessage
接受一个 callback
参数,一旦结果可用,该参数将被调用以将结果传回调用代码。
function getMessage(callback) {
setTimeout(function() {
callback('Hello asynchronous world!');
}, 0);
}
getMessage(function(message) {
console.log(message);
});
承诺
Promises 提供了一种比回调更灵活的替代方案,因为它们可以自然地组合起来以协调多个异步操作。Node.js Promises/A+ 和 Bluebird 等库中实现 Q .
function getMessage() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('Hello asynchronous world!');
}, 0);
});
}
getMessage().then(function(message) {
console.log(message);
});
jQuery 延迟
jQuery 通过其 Deferreds 提供了与承诺类似的功能。
function getMessage() {
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve('Hello asynchronous world!');
}, 0);
return deferred.promise();
}
getMessage().done(function(message) {
console.log(message);
});
异步/等待
如果你的 JavaScript 环境包含对 async
和 await
函数 async
内同步使用 promise
function getMessage () {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('Hello asynchronous world!');
}, 0);
});
}
async function main() {
let message = await getMessage();
console.log(message);
}
main();