Javascript 覆盖回调的范围
Javascript overwrite the scope of a callback
我最近偶然发现了这个问题,经过一段时间的阅读,我找不到特别满足这个用例的答案。
我正在尝试在javascript中实现以下行为
// Lets assume we have some variable defined in global scope
var a = {val: 0}
// What I want here is a function that sets a.val = newVal
// and then calls the callback.
var start = function(newVal, cb) {
???
}
// such that
start(1, function() {
setTimeout(function() {
console.log(a.val) // 1
}, 1000)
})
// and
start(2,function () {
console.log(a.val) // 2
})
// but in the original scope
console.log(a.val) // 0
换句话说,我正在寻找一种将回调"包装"在不同的全局范围内的方法。我知道你可以做类似的事情传递环境或使用它;但是这样的方法总是强制回调函数显式引用环境,将回调代码转换为类似
start(2,function () {
console.log(env.a.val) // 2
})
我特别在寻找一种解决方案,该解决方案保留了直接从 start 回调中使用全局引用的可能性。
随意使用任何可以以某种方式填充或与节点兼容的 ES6/ES7 功能,这不仅仅是为了生产代码而只是一种有趣的练习。
编辑:我将解释一般问题,因为许多人认为此解决方案可能不是我实际想要的。
我最近了解了STM(https://wiki.haskell.org/Software_transactional_memory(并希望在JS中尝试类似的想法。当然,js 在单个线程上运行,但这个想法是为原子块中运行的不同回调提供相同级别的隔离。
用户具有某种共享事务变量。对此的操作变量必须包装在原子块中。幕后发生的事情是,原子块中的操作不是在实际的TVar上执行的,而是在一些MockTVar上执行的,它只是将所有读写记录在日志中。调用 done 时,将检查日志以查看执行的操作是否与 TVars 的当前状态一致;如果是现在在实际 TVars 上执行的更新并且我们完成了(这称为提交(。如果不是,则丢弃日志并再次运行回调。这是代码的一个小示例
var x = new TVar(2)
// this is process a
process.nextTick(function() {
atomically(x, function(x, done) {
a = x.readTVar()
setTimeout(function() {
x.writeTVar(a+1)
console.log('Process a increased, x = ', x.readTVar())
done()
}, 2000)
})
})
// this is process b
process.nextTick(function() {
atomically(x, function(x, done) {
var a = x.readTVar()
x.writeTVar(a+1)
console.log('Process b increased, x = ', x.readTVar())
done()
})
}(
在此示例中,进程 a 将尝试提交,但由于进程 b 更改了 x 的值(并在 a 之前提交了该更改(,提交将失败,回调将再次运行。
如您所见,我在回调中返回了 mockTVars,但我觉得这有点丑陋,原因有两个:1(如果你想锁定多个变量(你通常会这样做(,我别无选择,只能返回一个模拟TVars数组,迫使用户如果他想干净地使用它们,就一个接一个地提取它们。2(如果用户希望能够在不失去理智的情况下推理正在发生的事情,则由用户来确保传递给回调的mockTVar的名称与实际TVar的名称匹配。我的意思是,在这一行中
atomically(x, function(x, done) {..})
由用户使用相同的名称来引用实际的 TVar 和模拟的 TVar(在本例中名称为 x(。
我希望这个解释是有帮助的。感谢所有花时间帮助我的人
我仍然希望您描述您尝试解决的实际问题,但这里有一个想法,即创建全局对象的副本,将其传递给回调,回调可以使用与全局相同的名称,然后它将"覆盖"对该范围的全局访问。
var a = {val: 0, otherVal: "hello"} ;
function start(newVal, cb) {
var copy = {};
Object.assign(copy, a);
copy.val = newVal;
cb(copy);
}
log("Before start, a.val = " + a.val);
start(1, function(a) {
// locally scoped copy of "a" here that is different than the global "a"
log("Beginning of start, a.val = " + a.val) // 1
a.val = 2;
log("End of start, a.val = " + a.val) // 2
});
log("After start, a.val = " + a.val);
function log(x) {
document.write(x + "<br>");
}
- 嵌套回调范围和rootScope AngularJS
- 在 Angular 指令中,如何进行回调,其中函数名称位于父范围的变量中
- 角承诺的“then”函数的成功回调的词汇范围是什么?
- NodeJS回调范围问题
- 绑定promise回调函数的“this”范围
- 集合回调忽略范围变量
- 回调函数的词法范围
- 将“this”范围传递给回调函数
- 回调中变量的范围
- 更改 JavaScript 中回调的全局范围
- Javascript 回调中的范围
- Javascript 覆盖回调的范围
- 反应组件 JSON 回调范围
- chrome.serial.connect 回调范围问题
- Javascript(NodeJS)回调范围
- 尝试在Fancybox回调内调用CoffeeScript方法时出现范围问题
- 函数回调超出范围
- 在Angular controller's回调,为什么参数必须命名为“$“范围”;
- 试图通过填充对象来理解函数和回调范围
- Javascript从另一个回调访问对象变量,而不将变量放在全局范围内