Я наткнулся на эту проблему недавно, и через некоторое время я не мог найти ответ, который удовлетворяет этому варианту использования, в частности.Javascript переписывает область обратного вызова
Я пытаюсь добиться следующего поведения в 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
})
Я специально искал решение, которое сохраняет возможность использовать глобальную ссылку непосредственно из обратного вызова начала.
Не стесняйтесь использовать любую ES6/ES7 функцию, которая может каким-то образом быть смонтирована или совместима с узлом, это не предназначено для производственного кода просто весело.
EDIT: Я объясню общую проблему, поскольку многие люди предположили, что это решение может и не быть тем, что я действительно ищу.
Недавно я узнал о STM (https://wiki.haskell.org/Software_transactional_memory) и хотел поиграть с подобной идеей в js. Конечно, js работает на одном потоке, но идея заключалась в том, чтобы обеспечить одинаковый уровень изоляции для разных обратных вызовов, работающих в атомных блоках.
Пользователь имеет некоторую общую транзакционную переменную. Операции над этой переменной должны быть обернуты атомарными блоками. Что происходит под капотом, так это то, что операции в атомарном блоке выполняются не на реальном TVar, а на каком-то MockTVar, который просто записывает все записи и записи в журнале. Когда вы вызываете выполненный, журнал проверяется, соответствуют ли выполняемые операции текущему состоянию телевизоров; если это обновления, которые теперь выполняются на реальных ТВАРАх, и мы закончили (это называется фиксацией). Если это не журнал, отбрасывается и обратный вызов запускается снова. Это небольшой пример кода
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()
})
})
В этом примере процессе а будет пытаться совершить, но так как процесс б изменил значение х (и совершенным, что изменение перед) фиксацией воли fail, и обратный вызов будет запущен еще раз.
Как вы можете видеть, я возвращаю mockTVars в обратном вызове, но я считаю это немного уродливым по двум причинам: 1) Если вы хотите заблокировать более одной переменной (и, как правило, вы делаете), у меня нет выбора но возвращать массив mockTVars, заставляя пользователя извлекать их один за другим, если он хочет использовать их в чистоте. 2) Пользователь должен убедиться, что имя mockTVar, которое передано обратному вызову, соответствует имени реального TVar, если он хочет иметь возможность рассуждать о том, что происходит, не теряя рассудка. То, что я имею в виду, что в этой строке
atomically(x, function(x, done) {..})
Это до пользователя, чтобы использовать то же имя для обозначения как к фактическому TVAR и издевались TVAR (имя х в данном примере).
Надеюсь, это объяснение поможет.Спасибо всем, кто нашел время, чтобы помочь мне
Почему вы пытаетесь сделать это? убедитесь, что это не проблема [xy] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) – jeremy
Я думаю, что этот тип вещей возможен только в команде lisp с макросами или в Emacs lisp с динамическими переменными. – jcubic
Вы, по сути, спрашиваете, как использовать одну переменную для хранения нескольких значений, что невозможно. – michael