Как реализован стек асинхронных вызовов - PullRequest
0 голосов
/ 12 марта 2019

Скажем, у вас есть эта последовательность функций (JavaScript) ....

A(function(){
  console.log('done')
})

function A(done) {
  a()
  B(D, done)
}

function B(x, y) {
  x(function(){
    c()
    C(y)
    d()
  })
}

function C(z) {
  g()
  setTimeout(z, 1000)
}

function D(z) {
  h()
  setTimeout(z, 2000)
}

function a() {
  b()
  c()
}

function b() {
  // ... sync stuff
}

function c() {
  e()
  // ... sync stuff
  f()
}

function d() {
  // ... sync stuff
}

Попытка сделать так, чтобы она имела своего рода сложный стек вызовов.

Что мне интересно, так этокак выглядит стек вызовов в разные моменты времени.Например, последовательность c();C(y);d().Когда вызывается c(), функция next , вызываемая на этом уровне, равна C().Таким образом, кажется, что это подтолкнет в стек (до оценки c()), что C() - это место возврата.Затем он переходит к e() и f() (игнорируя это на данный момент).Затем он проверяет стек вызовов и возвращается к C().Тогда тот же процесс.Но поскольку C() является асинхронным, он переходит к d() до завершения C().Вот как это выглядит:

c   c   c   c   c   c     c    ...?
    C   C   C   C   C    /  \
        e   e   f       C    d
            f

Вот куда я отправляюсь, пытаясь отобразить стек вызовов.Кажется, что это сформировало бы дерево.Теперь представьте несколько асинхронных процессов, начинающихся одновременно.Тогда это как множественные ветви на дерево.Таким образом, вместо стека вызовов, дерево вызовов.Это заставляет меня наконец задаться вопросом, как именно оценивается стек вызовов. Когда следующая функция в последовательности помещается в стек вызовов, и как обновляют / удаляют последнюю завершенную функцию и возвращаются к следующему месту в стеке вызовов /tree.

Хотите знать, можете ли вы указать какие-либо ресурсы, которые могли бы описать это, или, возможно, даже объяснить, как будет выглядеть стек вызовов в примере, который я описал выше.

1 Ответ

1 голос
/ 12 марта 2019

Когда вы вызываете функцию, вы помещаете адрес возврата в стек, а не следующую вызываемую функцию. Затем вызываемая функция создаст свой собственный кадр в стеке (вы можете рассмотреть часть адреса возврата этого кадра или отделиться от кадра, в зависимости от того, как вы на него смотрите. Когда функция вернется, она вытолкнет свой кадр и вернется к обратный адрес (который также неявно или явно выталкивает обратный адрес - детали зависят от архитектуры CPU / VM.

Так что для вашего примера стек вызовов со временем выглядит больше как

c c c c c C C
  e   f     g
...