所以我正在使用 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。
setTimeout 部分是我推测的部分,它将调用推送到事件循环的下一个滴答。但是,我完全迷失在代码的返回部分。
Q) 我知道 intv 将是计时器 ID,orgin_fn.bind.apply 的黑魔法到底是什么意思。我知道 bind,ahem 将一个值绑定(bind)到一个稍后调用的函数,apply 传递一个 this 对象和参数数组,但我很难理解整个调用流程,而且我从未见过 fb.bind.apply。
问)当我在浏览器中运行代码时,此对象解析为窗口,为什么所有参数都连接在窗口(在本例中为全局)对象上。
问)我知道这是 POC,但是是否有合理的理由在这里有一个 else block 来以任何方式执行函数。在哪种情况下我会看到它正在执行。
干杯!
最佳答案
orig_fn.bind.apply
用于替换同步回调。它正在创建一个新函数,该函数在被调用时将使用相同的 this
和调用它(替换)的参数调用原始函数,并将该函数分配给 fn
.这是为了稍后当计时器关闭并调用 fn
时,它会使用正确的 this
和参数调用原始函数。 (参见 Function#bind
和 Function#apply
;棘手的一点是它在 bind
本身上使用 apply
,将 orig_fn
作为 this
用于 bind
调用。)
if
/else
是这样的,如果在计时器关闭之前调用替换(intv
为真),它不会t 立即调用 orig_fn
,它等待执行上述操作并将结果分配给 fn
。但是,如果计时器已关闭(intv
为 null
,因此为 falsy),它会立即同步调用原始函数。
通常,您不会希望创建一个像那样困惑的函数(有时异步执行某事,有时同步执行),但在这种特殊情况下,原因是它确保它包装的函数是 总是 异步调用:如果在调用 asyncify
时在同一个作业/任务*期间调用该函数,它会等待调用原始函数,直到计时器触发;但如果它已经在执行不同的工作/任务,它会立即执行。
该函数的更现代版本可能会使用 promise ,因为在当前环境中, promise 结算回调会在当前作业之后尽快发生;在浏览器上,这意味着它发生在定时器回调之前。 (Promise 结算回调是所谓的“微任务”与计时器和事件“宏任务”。在宏任务期间安排的任何微任务在该宏任务完成时执行,先于任何先前安排的下一个宏任务。)
* 工作 = JavaScript terminology , 任务 = browser terminology
关于javascript - 强制回调异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47164303/