所以我正在使用this指南来了解JS中的异步行为。我无法解开的例子就是这个
function asyncify(fn) {
var orig_fn = fn,
intv = setTimeout( function(){
intv = null;
if (fn) fn();
}, 0 )
;
fn = null;
return function() {
// firing too quickly, before `intv` timer has fired to
// indicate async turn has passed?
if (intv) {
fn = orig_fn.bind.apply(
orig_fn,
// add the wrapper's `this` to the `bind(..)`
// call parameters, as well as currying any
// passed in parameters
[this].concat( [].slice.call( arguments ) )
);
}
// already async
else {
// invoke original function
orig_fn.apply( this, arguments );
}
};
}
用法:
function result(data) {
console.log( a );
}
var a = 0;
ajax( "..pre-cached-url..", asyncify( result ) );
a++;
所以从概念上讲,我理解它试图强制一个立即执行的函数,在事件循环的下一个刻度上运行,这允许变量a设置为值1,因此将始终打印1。 / p>
setTimeout部分是我假设的部分,它将调用推送到事件循环的下一个tick。但是,我完全迷失在代码的返回部分。
问)我知道intv将是计时器ID,究竟是orgin_fn.bind.apply的黑魔法意味着什么。我知道bind,ahem将一个值绑定到稍后要调用的函数,apply会传递一个this对象和参数数组,但是我很难理解整个调用流程,而且我从未见过fb.bind.apply。 / p>
Q)当我在浏览器中运行代码时,此对象解析为Window,为什么所有参数都在窗口(本例中为全局)对象上连接。
问)我理解这是POC,但是有一个合理的理由在这里有一个以任何方式执行函数的else块。我在哪种情况下看到这个被执行。
干杯!
答案 0 :(得分:1)
orig_fn.bind.apply
是替代同步回调。它正在创建一个新函数,当调用它时,将使用相同的this
调用原始函数并调用它(替换),并将该函数分配给fn
。这样,以后当计时器关闭并调用fn
时,它会使用正确的this
和参数调用原始函数。 (请参阅Function#bind
和Function#apply
;棘手的一点是它在apply
上使用bind
,为orig_fn
传递this
bind
{1}}致电。)
if
/ else
是这样的,如果在计时器关闭之前调用替换(intv
是真的),它就不会立即调用orig_fn
,它等待上述操作并将结果分配给fn
。但是如果计时器已经关闭(intv
为null
并且因此是假的),它会立即同步调用原始函数。
通常情况下,您不希望创建一个像这样混乱的函数(有时异步执行某些操作,有时同步执行),但在这种特殊情况下,原因是它确保它包装的函数是始终异步调用:如果在调用asyncify
的同一作业/任务*期间调用该函数,它将等待调用原始函数,直到计时器触发为止;但是如果它已经在不同的工作/任务上,那么它就会立即完成。
该功能的更现代版本可能使用承诺,因为在当前环境中,承诺结算回调在当前作业之后尽快发生;在浏览器上,这意味着它发生在计时器回调之前。 (Promise解决回调是所谓的“微任务”与计时器和事件“macrotasks”。在macrotask完成时,在任何先前安排的下一个macrotask之前执行macackask期间安排的任何微任务。)
* job = JavaScript terminology,task = browser terminology