Aug-16-2017, 04:09 AM
Earlier today, I had the opportunity (lol) to write a javascript fallback function for Promises for browsers which don't support Promises. Which... is pretty much only IE (edge supports them just fine). For reference: https://developer.mozilla.org/en-US/docs...ts/Promise
The basic idea, is that you create a promise and immediately return it, so the caller can attach callbacks which will be called when the Promise is fulfilled (...when the callee fullfills it's Promise that it'll eventually finish). The use case for javascript is to make code look less disgusting when working with ajax calls.
For example, let's say you had a function
And it turns out... not very difficult at all.
The basic idea, is that you create a promise and immediately return it, so the caller can attach callbacks which will be called when the Promise is fulfilled (...when the callee fullfills it's Promise that it'll eventually finish). The use case for javascript is to make code look less disgusting when working with ajax calls.
For example, let's say you had a function
get(url)
, which took, as a string argument, the url to request, and returned a Promise. You could then write the following:get("/some_content.json") .then(function(data) { alert(data); }); console.log("this will happen before the ajax callback");It's basically just syntactic sugar, and is mostly useless now that javascript supports async/await, but that's beside the point. The point is that it's actually pretty neat, and one of the cool parts is that you can chain data from one promise to the next, to create semi-functional programs. And it got me to wondering how hard it would be to writing the same functionality in Python.
And it turns out... not very difficult at all.
class STATES: Pending = 0 Resolved = 1 Rejected = 2 class Promise: def __init__(self, worker): keys = [STATES.Resolved, STATES.Rejected] self.state = STATES.Pending self.callbacks = {key: [ ] for key in keys} self.content = {key: None for key in keys} def callback_generator(state): def callback(response=None): self.content[state] = response self.state = state self.__run(state) return callback worker( callback_generator(STATES.Resolved), callback_generator(STATES.Rejected) ) def __run(self, key): # a callback is only ever called a single time while self.callbacks[key]: callback = self.callbacks[key].pop(0) # chain the output of one callback into the input of the next response = callback(self.content[key]) if response is not None: self.content[key] = response def __chain_method(self, state, callback): self.callbacks[state].append(callback) # register the new promise's callbacks with the parent, so data/errors # will chain def worker(resolve, fail): self.callbacks[STATES.Resolved].append(resolve) self.callbacks[STATES.Rejected].append(fail) future = Promise(worker) future.content = self.content future.state = self.state if self.state == state: self.__run(state) return future def then(self, callback): return self.__chain_method(STATES.Resolved, callback) def catch(self, callback): return self.__chain_method(STATES.Rejected, callback) if __name__ == "__main__": def callback(resolve, fail): print("before resolve") resolve(5) print("after resolve") # fail(Exception("boop")) future = Promise(callback) future.then(lambda x: x**2).then(print) #.catch(lambda err: print(f"Uh oh: {err}"))