Module: Puppeteer::Bidi::AsyncUtils

Extended by:
AsyncUtils, AsyncUtils
Included in:
AsyncUtils
Defined in:
lib/puppeteer/bidi/async_utils.rb,
sig/_supplementary.rbs,
sig/puppeteer/bidi/async_utils.rbs

Overview

Utility methods for working with Async tasks Provides Promise.all and Promise.race equivalents using Async::Barrier

Instance Method Summary collapse

Instance Method Details

#async_timeout(timeout_ms, task = nil) {|async_task| ... } ⇒ Async::Task

Execute a task with a timeout using Async::Task#with_timeout

Parameters:

  • timeout_ms (Numeric)

    Timeout duration in milliseconds

  • task (Proc, Async::Promise, nil) (defaults to: nil)

    Task to execute; falls back to block

Yields:

  • (async_task)

    Execute a task within the timeout, optionally receiving Async::Task

Returns:

  • (Async::Task)

    Async task that resolves/rejects once the operation completes



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/puppeteer/bidi/async_utils.rb', line 30

def async_timeout(timeout_ms, task = nil, &block)
  if task
    return Async do |async_task|
      if timeout_ms == 0
        if task.is_a?(Proc)
          args = task.arity.positive? ? [async_task] : []
          task.call(*args)
        else
          await(task)
        end
      else
        timeout_seconds = timeout_ms / 1000.0
        async_task.with_timeout(timeout_seconds) do
          if task.is_a?(Proc)
            args = task.arity.positive? ? [async_task] : []
            task.call(*args)
          else
            await(task)
          end
        end
      end
    end
  end

  if block
    return Async do |async_task|
      if timeout_ms == 0
        args = block.arity.positive? ? [async_task] : []
        await(block.call(*args))
      else
        timeout_seconds = timeout_ms / 1000.0
        async_task.with_timeout(timeout_seconds) do
          args = block.arity.positive? ? [async_task] : []
          await(block.call(*args))
        end
      end
    end
  end

  raise ArgumentError, 'AsyncUtils.async_timeout requires a task or block'
end

#await(task) ⇒ Object

Parameters:

  • task (Object)

Returns:

  • (Object)


15
16
17
18
19
20
21
22
23
# File 'lib/puppeteer/bidi/async_utils.rb', line 15

def await(task)
  if task.is_a?(Proc)
    task.call
  elsif task.respond_to?(:wait)
    task.wait
  else
    task
  end
end

#await_promise_all(*tasks) ⇒ Array

Wait for all async tasks to complete and return results Similar to Promise.all in JavaScript

Examples:

With procs

results = AsyncUtils.await_promise_all(
  -> { sleep 0.1; "first" },
  -> { sleep 0.2; "second" },
  -> { sleep 0.05; "third" }
)
# => ["first", "second", "third"]

With promises

promise1 = Async::Promise.new
promise2 = Async::Promise.new
Thread.new { sleep 0.1; promise1.resolve("first") }
Thread.new { sleep 0.2; promise2.resolve("second") }
results = AsyncUtils.await_promise_all(promise1, promise2)
# => ["first", "second"]

Parameters:

Returns:

  • (Array)

    Array of results in the same order as the input tasks

Raises:

  • If any task raises an exception, it will be propagated



95
96
97
# File 'lib/puppeteer/bidi/async_utils.rb', line 95

def await_promise_all(*tasks)
  Sync { zip(*tasks) }
end

#await_promise_race(*tasks) ⇒ Object

Race multiple async tasks and return the result of the first one to complete Similar to Promise.race in JavaScript

Examples:

With procs

result = AsyncUtils.await_promise_race(
  -> { sleep 1; "slow" },
  -> { sleep 0.1; "fast" }
)
# => "fast"

With promises

promise1 = Async::Promise.new
promise2 = Async::Promise.new
Thread.new { sleep 0.3; promise1.resolve("slow") }
Thread.new { sleep 0.1; promise2.resolve("fast") }
result = AsyncUtils.await_promise_race(promise1, promise2)
# => "fast"

Parameters:

Returns:

  • The result of the first task to complete



121
122
123
# File 'lib/puppeteer/bidi/async_utils.rb', line 121

def await_promise_race(*tasks)
  Sync { first(*tasks) }
end

#first(*tasks) ⇒ Object

Parameters:

  • tasks (Object)

Returns:

  • (Object)


148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/puppeteer/bidi/async_utils.rb', line 148

def first(*tasks)
  barrier = Async::Barrier.new
  result = nil

  begin
    tasks.each do |task|
      barrier.async do
        await(task)
      end
    end

    # Wait for the first task to complete
    barrier.wait do |completed_task|
      result = completed_task.wait
      break # Stop waiting after the first task completes
    end

    result
  ensure
    # Cancel all remaining tasks
    barrier.stop
  end
end

#promise_all(*tasks) ⇒ Object

Parameters:

  • tasks (Object)

Returns:

  • (Object)


72
73
74
# File 'lib/puppeteer/bidi/async_utils.rb', line 72

def promise_all(*tasks)
  Async { zip(*tasks) }
end

#promise_race(*tasks) ⇒ Object

Parameters:

  • tasks (Object)

Returns:

  • (Object)


100
101
102
# File 'lib/puppeteer/bidi/async_utils.rb', line 100

def promise_race(*tasks)
  Async { first(*tasks) }
end

#zip(*tasks) ⇒ Object

Parameters:

  • tasks (Object)

Returns:

  • (Object)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/puppeteer/bidi/async_utils.rb', line 127

def zip(*tasks)
  barrier = Async::Barrier.new
  results = Array.new(tasks.size)

  tasks.each_with_index do |task, index|
    barrier.async do
      results[index] = await(task)
    end
  end

  begin
    # Wait for all tasks to complete
    barrier.wait
    results
  ensure
    # Promise.all rejects as soon as a task fails. Stop pending siblings so
    # callers that time out do not leave fibers waiting on unresolved promises.
    barrier.stop
  end
end