提问:如何获取以下代码中的data?
function fn(callback){
setTimeout(function (){
var data = 'hello';
},1000);
}
我们通常会想到以下两种方式(但是以下两种方法都获取不到异步操作的结果):
(1)直接在定时器中返回data
function fn(callback){
setTimeout(function (){
var data = 'hello';
return data;
},1000);
}
console.log(fn()); //undefined
结果是undefined,我们并没有拿到定时器函数里面的 data。为什么呢?
我们知道 setTimeout 是一个异步函数,它不进入主线程、而进入"任务队列",只有等主线程任务执行完毕,"任务队列"才开始通知主线程,请求执行任务,该任务才会进入主线程执行。
所以fn函数的执行顺序应该是:
- 执行fn()的时候,发现异步函数 setTimeout,不会立即执行,而是将它放到任务队列中。
- 由于没有直接给fn函数一个return 返回值,所以它的默认的是return undefined。console.log(fn())的结果是 undefined。所以我们并没能得到 setTimeout里面的data,因为此时根本还没有执行setTimeout函数里面的回调函数。
- 主线程任务执行完毕, setTimeout 时间到了之后,主线程开始执行 setTimeout里面的回调函数,返回data。
(2)在函数fn中返回data
function fn(callback){
var data = '';
setTimeout(function (){
var data = 'hello';
},1000);
return data;
}
console.log(fn()); // ''
运行结果为空,返回了一个空字符串。原因在于setTimeout中的回调函数还没有执行之前,fn就已经返回data了。
正确的解决方法:采用回调函数
在JavaScript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。
js代码会至上而下一条线执行下去,但是有时候我们需要等到一个操作结束之后再进行下一个操作,这时候就需要用到回调函数。
//如果需要获取一个函数中异步操作的结果,则必须通过回调函数来获取
function fn(callback){
//var callback = function(data){console.log(data);}
setTimeout(function (){
var data = 'hello';
callback(data);
},1000);
}
fn(function (data){
console.log(data);
})
以上代码的执行顺序是:
- 进入 fn 函数体
- 发现异步函数 setTimeout,将它放到任务队列中
- 1s以后执行 setTimeout 回调函数
- 在setTimeout 回调函数里执行
callback(data)
相当于立即执行:function (data){ console.log(data); })
,输出data值