How to make a promise from setTimeout

This is not a real world problem, I'm just trying to understand how promises are created.

I need to understand how to make a promise for a function that returns nothing, like setTimeout.

Suppose I have:

function async(callback){ setTimeout(function(){ callback(); }, 5000); } async(function(){ console.log('async called back'); }); 

How to create a promise that async can return after setTimeout ready for callback() ?

I assumed it would be somewhere:

 function setTimeoutReturnPromise(){ function promise(){} promise.prototype.then = function() { console.log('timed out'); }; setTimeout(function(){ return ??? },2000); return promise; } 

But I can’t think about it.

+45
javascript promise settimeout
Mar 28 '14 at 8:18
source share
1 answer

Update (2017)

Here, in 2017, Promises are built into JavaScript, they were added by the ES2015 specification (policies are available for legacy environments such as IE8-IE11). The syntax they used uses a callback that you pass to the Promise constructor ( Promise executor), which receives functions to allow / reject the promise as arguments.

Firstly, since async now makes sense in JavaScript (although this is only a keyword in certain contexts), I will use later as a function name to avoid confusion.

Base delay

Using native Promises (or true polyfill), it will look like this:

 function later(delay) { return new Promise(function(resolve) { setTimeout(resolve, delay); }); } 

Note that this assumes a version of setTimeout that matches the definition for browsers , where setTimeout does not pass any arguments to the callback if you don't give them after the interval (this may not be true in non-working environments and was not true in Firefox, but now it true in Chrome and even in IE8).

Base delay with value

If you want your function to additionally pass the resolution value, on any vaguely modern browser that allows you to give additional setTimeout arguments after a delay, and then passes them to the callback when called, you can do this (current Firefox and Chrome; IE11 + , presumably Edge; not IE8 or IE9, I don't know about IE10):

 function later(delay, value) { return new Promise(function(resolve) { setTimeout(resolve, delay, value); // Note the order, `delay` before `value` /* Or for outdated browsers that don't support doing that: setTimeout(function() { resolve(value); }, delay); Or alternately: setTimeout(resolve.bind(null, value), delay); */ }); } 

If you use the ES2015 + arrow functions, this may be more concise:

 function later(delay, value) { return new Promise(resolve => setTimeout(resolve, delay, value)); } 

or even

 const later = (delay, value) => new Promise(resolve => setTimeout(resolve, delay, value)); 

Cancel delay with value

If you want to cancel the timeout, you cannot just return the promise from later , because Promises cannot be canceled.

But we can easily return the object using the cancel method and the accessory for the promise and reject the promise of cancellation:

 const later = (delay, value) => { let timer = 0; let reject = null; const promise = new Promise((resolve, _reject) => { reject = _reject; timer = setTimeout(resolve, delay, value); }); return { get promise() { return promise; }, cancel() { if (timer) { clearTimeout(timer); timer = 0; reject(); reject = null; } } }; }; 

Live example:

 const later = (delay, value) => { let timer = 0; let reject = null; const promise = new Promise((resolve, _reject) => { reject = _reject; timer = setTimeout(resolve, delay, value); }); return { get promise() { return promise; }, cancel() { if (timer) { clearTimeout(timer); timer = 0; reject(); reject = null; } } }; }; const l1 = later(100, "l1"); l1.promise .then(msg => { console.log(msg); }) .catch(() => { console.log("l1 cancelled"); }); const l2 = later(200, "l2"); l2.promise .then(msg => { console.log(msg); }) .catch(() => { console.log("l2 cancelled"); }); setTimeout(() => { l2.cancel(); }, 150); 



Original answer from 2014

Usually you will have a library of promises (one you write yourself or one of them). This library usually has an object that you can create and then β€œallow,” and that object will have a β€œpromise” that you can receive from it.

Then later will look something like this:

 function later() { var p = new PromiseThingy(); setTimeout(function() { p.resolve(); }, 2000); return p.promise(); // Note we're not returning `p` directly } 



In a comment on the question, I asked:

Are you trying to create your own promise library?

and you said

I was not, but now I think that in fact I was trying to understand. This is how the library will do it.

To help this understanding, here is a very simple example that is not remotely Promises -A compatible: Live Copy

 <!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <title>Very basic promises</title> </head> <body> <script> (function() { // ==== Very basic promise implementation, not remotely Promises-A compliant, just a very basic example var PromiseThingy = (function() { // Internal - trigger a callback function triggerCallback(callback, promise) { try { callback(promise.resolvedValue); } catch (e) { } } // The internal promise constructor, we don't share this function Promise() { this.callbacks = []; } // Register a 'then' callback Promise.prototype.then = function(callback) { var thispromise = this; if (!this.resolved) { // Not resolved yet, remember the callback this.callbacks.push(callback); } else { // Resolved; trigger callback right away, but always async setTimeout(function() { triggerCallback(callback, thispromise); }, 0); } return this; }; // Our public constructor for PromiseThingys function PromiseThingy() { this.p = new Promise(); } // Resolve our underlying promise PromiseThingy.prototype.resolve = function(value) { var n; if (!this.p.resolved) { this.p.resolved = true; this.p.resolvedValue = value; for (n = 0; n < this.p.callbacks.length; ++n) { triggerCallback(this.p.callbacks[n], this.p); } } }; // Get our underlying promise PromiseThingy.prototype.promise = function() { return this.p; }; // Export public return PromiseThingy; })(); // ==== Using it function later() { var p = new PromiseThingy(); setTimeout(function() { p.resolve(); }, 2000); return p.promise(); // Note we're not returning `p` directly } display("Start " + Date.now()); later().then(function() { display("Done1 " + Date.now()); }).then(function() { display("Done2 " + Date.now()); }); function display(msg) { var p = document.createElement('p'); p.innerHTML = String(msg); document.body.appendChild(p); } })(); </script> </body> </html> 
+39
Mar 28 '14 at 8:23
source share



All Articles