Promise python简单实现

Promise是JavaScript封装的原生对象,由于其特点配合异步操作可以在当遇到网络请求后更新页面数据的场景下,可以让代码非常优雅。

其特点就是通过它创建对象时,传入一个含两个函数参数(resolve, reject)的函数(后面成为函数A),当其内部调用resolve函数时,会来到后续的then函数执行相关操作;当其内部调用reject函数时,会来到后续的catch函数执行相关操作。

想着就此特点,用python封装一个类似的类,来提高编程思维。

首先要理好顺序,当Promise对象创建好后,应该是先执行传入的函数A,并且此时then后面的相关操作和catch后面的相关操作也应该要拿到,这样当函数中执行resolve时回调then后面的操作即可;当函数执行reject时回调catch后面的操作即可。

封装后如下:

 1 import requests
 2 
 3 class Promise:
 4 
 5     def __init__(self, func):
 6         self.func = func
 7         self.resolve_callbacks = None
 8         self.reject_callbacks = None
 9 
10     def resolve(self, value):
11         print("获取数据成功,正在回调then参数处理数据")
12         for resolve_callback in self.resolve_callbacks:
13             resolve_callback(value)
14 
15     def reject(self, errmsg):
16         print("获取数据失败,正在回调catch参数处理数据")
17         for reject_callback in self.resolve_callbacks:
18             reject_callback(errmsg)
19 
20     def then(self, *args):
21         self.resolve_callbacks = args
22 
23         return self
24 
25     def catch(self, *args):
26         self.reject_callbacks = args
27 
28         return self
29 
30     def __call__(self, *args, **kwargs):
31         self.func(self.resolve, self.reject)

理一下顺序:

  1. 首先创建Promise对象,会执行类的__init__方法,这时拿到了函数A
  2. 其次执行then方法,此时拿到了then后面的相关操作,该方法返回Promise对象本身,因此可以链式调用类的其他方法
  3. 然后执行catch方法,和then方法一样,拿到了catch方法后面的相关操作,该方法也需返回Promise对象本身,这里返回的原因如下:

  由于在python的类对象创建过程中,会先执行__new__方法给对象分配内存,其次执行__init__方法给对象初始化,执行__init__方法时不会执行其封装的其他函数,因此这时拿不到then和catch后续的操作,对象的两个属性resolve_callbacks和reject_callbacks都是None,所以这里需要当then和catch方法都执行完后,再通过某方式去调用函数A。最后选择了通过catch返回Promise类对象本身,后面加括号去调用__call__方法。

 

封装一下请求会成功的函数A如下:

 1 def get_response_success(resolve, reject):
 2     def inner():
 3         try:
 4             responseStr = requests.get("http://www.baidu.com", timeout=1).content.decode("utf-8")
 5         except requests.Timeout:
 6             reject({"errmsg": "请求数据失败"})
 7         else:
 8             resolve(responseStr)
 9 
10     inner()

封装一个请求会出错的函数A如下:

 1 def get_response_failed(resolve, reject):
 2     def inner():
 3         try:
 4             responseStr = requests.get("http://www.baidu.com", timeout=0.01).content.decode("utf-8")
 5         except requests.Timeout:
 6             reject({"errmsg": "请求数据失败"})
 7         else:
 8             resolve(responseStr)
 9 
10     inner()

传入执行如下:

1 Promise(get_response_success).then(lambda x: print(x)).catch(lambda x: print(x))()
2 Promise(get_response_failed).then(lambda x: print(x)).catch(lambda x: print(x))()
3 
4 # 获取数据成功,正在回调then参数处理数据
5 # <!DOCTYPE html>
6 # <!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title>此处省略。。。</html>
7 # 
8 # 获取数据失败,正在回调catch参数处理数据
9 # {'errmsg': '请求数据失败'}

补充一下,then和catch后续的操作我用了lambda匿名函数,为了方便理解写成两个便于理解的函数如下:

1 def then_func(result):
2     print(result)
3 
4 def catch_func(error):
5     print(error)
6 
7 Promise(get_response_success).then(then_func).catch(catch_func)()
8 Promise(get_response_failed).then(then_func).catch(catch_func)()


  • 作者:合十
  • 发表时间:2022年3月30日 23:50
  • 更新时间:2024年4月19日 19:47
  • 所属分类:我用Python

Comments

182fbvq_418
好好好好好