diff --git a/CHANGES b/CHANGES
index 0e638ca5a772a48533fb381cfd4c545283c802d9..a051c2968f1164d391b55ac98e85823f9eb1786b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -18,6 +18,13 @@ o Image.Dims.exif_get and Image.exif_decode
   according to the EXIF orientation information) without needing to check
   if the image is JPEG first.
 
+o Concurrent
+
+  - Add delay() to postpone a future.
+
+  - Rewrite timeout() to reduce the memory footprint of a future in the
+    common case.
+
 Bug fixes
 ---------
 
diff --git a/lib/modules/Concurrent.pmod b/lib/modules/Concurrent.pmod
index e31b37e11cd4115698c53944c1abf966bb803d50..eb91a0c88421918f03593ce9abe65a204aded559 100644
--- a/lib/modules/Concurrent.pmod
+++ b/lib/modules/Concurrent.pmod
@@ -91,8 +91,6 @@ class Future
 
   protected Pike.Backend backend;
 
-  protected array timeout_call_out_handle;
-
   //! Set the backend to use for calling any callbacks.
   //!
   //! @note
@@ -155,18 +153,7 @@ class Future
   //!   @[set_backend()], @[use_backend()]
   protected void call_callback(function cb, mixed ... args)
   {
-    if (timeout_call_out_handle) {
-      // Remove the timeout call_out, as it will not be relevant,
-      // but holds a reference to us.
-      (backend?backend->remove_call_out:remove_call_out)
-	(timeout_call_out_handle);
-      timeout_call_out_handle = UNDEFINED;
-    }
-    if (backend) {
-      backend->call_out(cb, 0, @args);
-    } else {
-      callout(cb, 0, @args);
-    }
+    (backend ? backend->call_out : callout)(cb, 0, @args);
   }
 
   //! Wait for fulfillment.
@@ -661,26 +648,45 @@ class Future
     return then(0, onrejected, @extra);
   }
 
-  //! Return a @[Future] that will either be fulfilled with the fulfilled
-  //! result of this @[Future], or be failed after @[seconds] have expired.
-  this_program timeout(int|float seconds)
+  private this_program setup_call_out(int|float seconds, void|int tout)
   {
+    array call_out_handle;
     Promise p = promise_factory();
+    void cancelcout(mixed value)
+    {
+      (backend ? backend->remove_call_out : remove_call_out)(call_out_handle);
+      p->try_success(0);
+    }
     /* NB: try_* variants as the original promise may get fulfilled
      *     after the timeout has occurred.
      */
-    on_failure(p->try_failure);
-    on_success(p->try_success);
-    if (timeout_call_out_handle) {
-      // Remove the previous timeout call_out.
-      (backend?backend->remove_call_out:remove_call_out)
-	(timeout_call_out_handle);
-    }
-    timeout_call_out_handle = (backend?backend->call_out:call_out)
-      (p->try_failure, seconds, ({ "Timeout.\n", backtrace() }));
+    on_failure(cancelcout);
+    call_out_handle = (backend ? backend->call_out : call_out)
+      (p[tout ? "try_failure" : "try_success"], seconds,
+       tout && ({ "Timeout.\n", backtrace() }));
+    if (tout)
+      on_success(cancelcout);
     return p->future();
   }
 
+  //! Return a @[Future] that will either be fulfilled with the fulfilled
+  //! result of this @[Future], or be failed after @[seconds] have expired.
+  this_program timeout(int|float seconds)
+  {
+    return first_completed(
+     ({ this_program::this, setup_call_out(seconds, 1) })
+    );
+  }
+
+  //! Return a @[Future] that will be fulfilled with the fulfilled
+  //! result of this @[Future], but not until at least @[seconds] have passed.
+  this_program delay(int|float seconds)
+  {
+    return results(
+     ({ this_program::this, setup_call_out(seconds) })
+    )->map(`[], 0);
+  }
+
   protected string _sprintf(int t)
   {
     return t=='O' && sprintf("%O(%s,%O)", this_program,
diff --git a/lib/modules/testsuite.in b/lib/modules/testsuite.in
index 891cafbcc9f2d058145077842eaa5c789c1452be..2b0e6de71c78d54df442a16c2be10893ae9a53e5 100644
--- a/lib/modules/testsuite.in
+++ b/lib/modules/testsuite.in
@@ -299,6 +299,109 @@ test_do([[ add_constant("p13"); ]])
 exit_promise(-1, 13)
 test_do([[ Concurrent.use_backend(1); ]]);
 
+dnl - Promise.timeout() - true
+init_promise()
+test_do([[ add_constant("p11", Concurrent.Promise()); ]])
+test_do([[ add_constant("p12", Concurrent.Promise()); ]])
+test_do([[ add_constant("p13", Concurrent.Promise()); ]])
+test_do([[ add_constant("p212", Concurrent.Promise()); ]])
+test_do([[ add_constant("future",
+            promise->depend(({p11->future(),p12->future()}))
+              ->depend(({}))->depend(p13->future())
+              ->depend(({p13->future(), p11->future(),
+             p212->timeout(0.01)
+              ->recover(lambda(mixed p) { return 212;})}))); ]])
+test_do([[ promise->depend()->success(14); ]])
+test_do([[ p13->success(13); ]])
+test_do([[ promise->depend()->success(15); ]])
+init_future()
+test_do([[ p11->success(11); ]])
+test_do([[ p12->success(12); ]])
+test_do([[ sleep(0.1); ]])
+test_do([[ add_constant("p11"); ]])
+test_do([[ add_constant("p12"); ]])
+test_do([[ add_constant("p13"); ]])
+test_do([[ add_constant("p212"); ]])
+exit_promise(1, ({11, 12, 13, 13, 11, 212, 14, 15}))
+
+dnl - Promise.timeout() - false
+init_promise()
+test_do([[ add_constant("p11", Concurrent.Promise()); ]])
+test_do([[ add_constant("p12", Concurrent.Promise()); ]])
+test_do([[ add_constant("p13", Concurrent.Promise()); ]])
+test_do([[ add_constant("p212", Concurrent.Promise()); ]])
+test_do([[ add_constant("future",
+            promise->depend(({p11->future(),p12->future()}))
+              ->depend(({}))->depend(p13->future())
+              ->depend(({p13->future(), p11->future(),
+             p212->timeout(9)
+              ->recover(lambda(mixed p) { return 212;})}))); ]])
+test_do([[ promise->depend()->success(14); ]])
+test_do([[ p13->success(13); ]])
+test_do([[ promise->depend()->success(15); ]])
+init_future()
+test_do([[ p11->success(11); ]])
+test_do([[ p12->success(12); ]])
+test_do([[ sleep(0.1); ]])
+test_do([[ p212->success(312); ]])
+test_do([[ add_constant("p11"); ]])
+test_do([[ add_constant("p12"); ]])
+test_do([[ add_constant("p13"); ]])
+test_do([[ add_constant("p212"); ]])
+exit_promise(1, ({11, 12, 13, 13, 11, 312, 14, 15}))
+
+dnl - Promise.delay() - false
+init_promise()
+test_do([[ add_constant("p11", Concurrent.Promise()); ]])
+test_do([[ add_constant("p12", Concurrent.Promise()); ]])
+test_do([[ add_constant("p13", Concurrent.Promise()); ]])
+test_do([[ add_constant("p212", Concurrent.Promise()); ]])
+test_do([[ add_constant("future",
+            promise->depend(({p11->future(),p12->future()}))
+              ->depend(({}))->depend(p13->future())
+              ->depend(({p13->future(), p11->future(),
+             p212->delay(9)
+              ->recover(lambda(mixed p) { return 212;})}))); ]])
+test_do([[ promise->depend()->success(14); ]])
+test_do([[ p13->success(13); ]])
+test_do([[ promise->depend()->success(15); ]])
+init_future()
+test_do([[ p11->success(11); ]])
+test_do([[ p12->success(12); ]])
+test_do([[ sleep(0.01); ]])
+test_do([[ p212->failure(12); ]])
+test_do([[ add_constant("p11"); ]])
+test_do([[ add_constant("p12"); ]])
+test_do([[ add_constant("p13"); ]])
+test_do([[ add_constant("p212"); ]])
+exit_promise(1, ({11, 12, 13, 13, 11, 212, 14, 15}))
+
+dnl - Promise.delay() - true
+init_promise()
+test_do([[ add_constant("p11", Concurrent.Promise()); ]])
+test_do([[ add_constant("p12", Concurrent.Promise()); ]])
+test_do([[ add_constant("p13", Concurrent.Promise()); ]])
+test_do([[ add_constant("p212", Concurrent.Promise()); ]])
+test_do([[ add_constant("future",
+            promise->depend(({p11->future(),p12->future()}))
+              ->depend(({}))->depend(p13->future())
+              ->depend(({p13->future(), p11->future(),
+             p212->delay(0.1)}))); ]])
+test_do([[ promise->depend()->success(14); ]])
+test_do([[ p13->success(13); ]])
+test_do([[ promise->depend()->success(15); ]])
+init_future()
+test_do([[ p11->success(11); ]])
+test_do([[ p12->success(12); ]])
+test_do([[ sleep(0.01); ]])
+test_do([[ p212->success(212); ]])
+test_do([[ add_constant("p11"); ]])
+test_do([[ add_constant("p12"); ]])
+test_do([[ add_constant("p13"); ]])
+test_do([[ add_constant("p212"); ]])
+test_do([[ sleep(0.1); ]])
+exit_promise(1, ({11, 12, 13, 13, 11, 212, 14, 15}))
+
 dnl - Promise.fold() - true
 init_promise()
 test_do([[ add_constant("p11", Concurrent.Promise()); ]])