关于generator异步编程的理解以及如何动手写 python异步有哪些方式

python generator\u662f\u4ec0\u4e48\u7c7b\u578b

generator\u662f\u4e00\u79cd\u7279\u6b8a\u7684\u51fd\u6570\uff0c\u548c\u4e00\u822c\u7684\u51fd\u6570\u4e0d\u540c\uff1a
\u4e00\u822c\u7684\u51fd\u6570\u8c03\u7528\u4e00\u6b21\uff0c\u603b\u4f1a\u7ed3\u675f\u8fd4\u56de\uff1bgenerator\u5374\u53ef\u4ee5\u6267\u884c\u5230\u67d0\u4e2a\u4f4d\u7f6e\u505c\u4f4f\uff0c\u901a\u8fc7yield\u8ba9\u51fa\u6267\u884c\u6743\uff0c\u4e0b\u6b21\u518d\u8c03\u7528\u65f6\uff0c\u4ece\u4e0a\u4e00\u6b21yield\u540e\u9762\u7684\u5730\u65b9\u5f00\u59cb\u6267\u884c\u3002
\u4f8b\u5982\uff1a\u4e0b\u9762\u7684\u4ee3\u7801\u53ef\u4ee5\u53cd\u590d\u8c03\u75284\u6b21generator\u51fd\u6570\u3002
def generator(): yield "a" yield "b" yield "c"for i in generator(): print(i);

yield\u76f8\u5f53\u4e8ereturn\uff0c\u4ed6\u5c06\u76f8\u5e94\u7684\u503c\u8fd4\u56de\u7ed9\u8c03\u7528next()\u6216\u8005send()\u7684\u8c03\u7528\u8005\uff0c\u4ece\u800c\u4ea4\u51fa\u4e86CPU\u4f7f\u7528\u6743\uff0c\u800c\u5f53\u8c03\u7528\u8005\u518d\u6b21\u8c03\u7528next()\u6216\u8005send()\u7684\u65f6\u5019\uff0c\u53c8\u4f1a\u8fd4\u56de\u5230yield\u4e2d\u65ad\u7684\u5730\u65b9\uff0c\u5982\u679csend\u6709\u53c2\u6570\uff0c\u8fd8\u4f1a\u5c06\u53c2\u6570\u8fd4\u56de\u7ed9yield\u8d4b\u503c\u7684\u53d8\u91cf,\u5982\u679c\u6ca1\u6709\u5c31\u548cnext\uff08\uff09\u4e00\u6837\u8d4b\u503c\u4e3aNone\u3002\u4f46\u662f\u8fd9\u91cc\u4f1a\u9047\u5230\u4e00\u4e2a\u95ee\u9898\uff0c\u5c31\u662f\u5d4c\u5957\u4f7f\u7528generator\u65f6\u5916\u5c42\u7684generator\u9700\u8981\u5199\u5927\u91cf\u4ee3\u7801\uff0c\u770b\u5982\u4e0b\u793a\u4f8b\uff1a \u6ce8\u610f\u4ee5\u4e0b\u4ee3\u7801\u5747\u5728Python3.6\u4e0a\u8fd0\u884c\u8c03\u8bd5
#!/usr/bin/env python# encoding:utf-8def inner_generator():i = 0while True:i = yield i if i > 10: raise StopIterationdef outer_generator():print("do something before yield")from_inner = 0from_outer = 1g = inner_generator()g.send(None) while 1: try:from_inner = g.send(from_outer)from_outer = yield from_inner except StopIteration: breakdef main():g = outer_generator()g.send(None)i = 0while 1: try:i = g.send(i + 1)print(i) except StopIteration: breakif __name__ == '__main__':main()1234567891011121314151617181920212223242526272829303132333435363738394041
\u4e3a\u4e86\u7b80\u5316\uff0c\u5728Python3.3\u4e2d\u5f15\u5165\u4e86yield from
yield from
\u4f7f\u7528yield from\u6709\u4e24\u4e2a\u597d\u5904\uff0c
1\u3001\u53ef\u4ee5\u5c06main\u4e2dsend\u7684\u53c2\u6570\u4e00\u76f4\u8fd4\u56de\u7ed9\u6700\u91cc\u5c42\u7684generator\uff0c 2\u3001\u540c\u65f6\u6211\u4eec\u4e5f\u4e0d\u9700\u8981\u518d\u4f7f\u7528while\u5faa\u73af\u548csend (), next()\u6765\u8fdb\u884c\u8fed\u4ee3\u3002
\u6211\u4eec\u53ef\u4ee5\u5c06\u4e0a\u8fb9\u7684\u4ee3\u7801\u4fee\u6539\u5982\u4e0b\uff1a
def inner_generator():i = 0while True:i = yield i if i > 10: raise StopIterationdef outer_generator():print("do something before coroutine start") yield from inner_generator()def main():g = outer_generator()g.send(None)i = 0while 1: try:i = g.send(i + 1)print(i) except StopIteration: breakif __name__ == '__main__':main()1234567891011121314151617181920212223242526
\u6267\u884c\u7ed3\u679c\u5982\u4e0b\uff1a
do something before coroutine start123456789101234567891011
\u8fd9\u91ccinner_generator()\u4e2d\u6267\u884c\u7684\u4ee3\u7801\u7247\u6bb5\u6211\u4eec\u5b9e\u9645\u5c31\u53ef\u4ee5\u8ba4\u4e3a\u662f\u534f\u7a0b\uff0c\u6240\u4ee5\u603b\u7684\u6765\u8bf4\u903b\u8f91\u56fe\u5982\u4e0b\uff1a
\u63a5\u4e0b\u6765\u6211\u4eec\u5c31\u770b\u4e0b\u7a76\u7adf\u534f\u7a0b\u662f\u5565\u6837\u5b50
\u534f\u7a0bcoroutine
\u534f\u7a0b\u7684\u6982\u5ff5\u5e94\u8be5\u662f\u4ece\u8fdb\u7a0b\u548c\u7ebf\u7a0b\u6f14\u53d8\u800c\u6765\u7684\uff0c\u4ed6\u4eec\u90fd\u662f\u72ec\u7acb\u7684\u6267\u884c\u4e00\u6bb5\u4ee3\u7801\uff0c\u4f46\u662f\u4e0d\u540c\u662f\u7ebf\u7a0b\u6bd4\u8fdb\u7a0b\u8981\u8f7b\u91cf\u7ea7\uff0c\u534f\u7a0b\u6bd4\u7ebf\u7a0b\u8fd8\u8981\u8f7b\u91cf\u7ea7\u3002\u591a\u7ebf\u7a0b\u5728\u540c\u4e00\u4e2a\u8fdb\u7a0b\u4e2d\u6267\u884c\uff0c\u800c\u534f\u7a0b\u901a\u5e38\u4e5f\u662f\u5728\u4e00\u4e2a\u7ebf\u7a0b\u5f53\u4e2d\u6267\u884c\u3002\u5b83\u4eec\u7684\u5173\u7cfb\u56fe\u5982\u4e0b\uff1a

\u6211\u4eec\u90fd\u77e5\u9053Python\u7531\u4e8eGIL(Global Interpreter Lock)\u539f\u56e0\uff0c\u5176\u7ebf\u7a0b\u6548\u7387\u5e76\u4e0d\u9ad8\uff0c\u5e76\u4e14\u5728*nix\u7cfb\u7edf\u4e2d\uff0c\u521b\u5efa\u7ebf\u7a0b\u7684\u5f00\u9500\u5e76\u4e0d\u6bd4\u8fdb\u7a0b\u5c0f\uff0c\u56e0\u6b64\u5728\u5e76\u53d1\u64cd\u4f5c\u65f6\uff0c\u591a\u7ebf\u7a0b\u7684\u6548\u7387\u8fd8\u662f\u53d7\u5230\u4e86\u5f88\u5927\u5236\u7ea6\u7684\u3002\u6240\u4ee5\u540e\u6765\u4eba\u4eec\u53d1\u73b0\u901a\u8fc7yield\u6765\u4e2d\u65ad\u4ee3\u7801\u7247\u6bb5\u7684\u6267\u884c\uff0c\u540c\u65f6\u4ea4\u51fa\u4e86cpu\u7684\u4f7f\u7528\u6743\uff0c\u4e8e\u662f\u534f\u7a0b\u7684\u6982\u5ff5\u4ea7\u751f\u4e86\u3002\u5728Python3.4\u6b63\u5f0f\u5f15\u5165\u4e86\u534f\u7a0b\u7684\u6982\u5ff5\uff0c\u4ee3\u7801\u793a\u4f8b\u5982\u4e0b\uff1a
import asyncio# Borrowed from http://curio.readthedocs.org/en/latest/[email protected] countdown(number, n):while n > 0:print('T-minus', n, '({})'.format(number)) yield from asyncio.sleep(1)n -= 1loop = asyncio.get_event_loop()tasks = [asyncio.ensure_future(countdown("A", 2)),asyncio.ensure_future(countdown("B", 3))]loop.run_until_complete(asyncio.wait(tasks))loop.close()12345678910111213141516
\u793a\u4f8b\u663e\u793a\u4e86\u5728Python3.4\u5f15\u5165\u4e24\u4e2a\u91cd\u8981\u6982\u5ff5\u534f\u7a0b\u548c\u4e8b\u4ef6\u5faa\u73af\uff0c \u901a\u8fc7\u4fee\u9970\[email protected]\u5b9a\u4e49\u4e86\u4e00\u4e2a\u534f\u7a0b\uff0c\u800c\u901a\u8fc7event loop\u6765\u6267\u884ctasks\u4e2d\u6240\u6709\u7684\u534f\u7a0b\u4efb\u52a1\u3002\u4e4b\u540e\u5728Python3.5\u5f15\u5165\u4e86\u65b0\u7684async & await\u8bed\u6cd5\uff0c\u4ece\u800c\u6709\u4e86\u539f\u751f\u534f\u7a0b\u7684\u6982\u5ff5\u3002
async & await
\u5728Python3.5\u4e2d\uff0c\u5f15\u5165\u4e86aync&await \u8bed\u6cd5\u7ed3\u6784\uff0c\u901a\u8fc7\u201daync def\u201d\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a\u534f\u7a0b\u4ee3\u7801\u7247\u6bb5\uff0c\u4f5c\u7528\u7c7b\u4f3c\u4e8ePython3.4\u4e2d\[email protected]\u4fee\u9970\u7b26\uff0c\u800cawait\u5219\u76f8\u5f53\u4e8e\u201dyield from\u201d\u3002
\u5148\u6765\u770b\u4e00\u6bb5\u4ee3\u7801\uff0c\u8fd9\u4e2a\u662f\u6211\u521a\u5f00\u59cb\u4f7f\u7528async&await\u8bed\u6cd5\u65f6\uff0c\u5199\u7684\u4e00\u6bb5\u5c0f\u7a0b\u5e8f\u3002
#!/usr/bin/env python# encoding:utf-8import asyncioimport requestsimport timeasync def wait_download(url):response = await requets.get(url)print("get {} response complete.".format(url))async def main():start = time.time()await asyncio.wait([wait_download("http://www.163.com"),wait_download("http://www.mi.com"),wait_download("http://www.google.com")])end = time.time()print("Complete in {} seconds".format(end - start))loop = asyncio.get_event_loop()loop.run_until_complete(main())12345678910111213141516171819202122232425
\u8fd9\u91cc\u4f1a\u6536\u5230\u8fd9\u6837\u7684\u62a5\u9519\uff1a
Task exception was never retrievedfuture: exception=TypeError("object Response can't be used in 'await' expression",)>Traceback (most recent call last):File "asynctest.py", line 10, in wait_downloaddata = await requests.get(url)TypeError: object Response can't be used in 'await' expression123456
\u8fd9\u662f\u7531\u4e8erequests.get()\u51fd\u6570\u8fd4\u56de\u7684Response\u5bf9\u8c61\u4e0d\u80fd\u7528\u4e8eawait\u8868\u8fbe\u5f0f\uff0c\u53ef\u662f\u5982\u679c\u4e0d\u80fd\u7528\u4e8eawait\uff0c\u8fd8\u600e\u4e48\u6837\u6765\u5b9e\u73b0\u5f02\u6b65\u5462\uff1f \u539f\u6765Python\u7684await\u8868\u8fbe\u5f0f\u662f\u7c7b\u4f3c\u4e8e\u201dyield from\u201d\u7684\u4e1c\u897f\uff0c\u4f46\u662fawait\u4f1a\u53bb\u505a\u53c2\u6570\u68c0\u67e5\uff0c\u5b83\u8981\u6c42await\u8868\u8fbe\u5f0f\u4e2d\u7684\u5bf9\u8c61\u5fc5\u987b\u662fawaitable\u7684\uff0c\u90a3\u5565\u662fawaitable\u5462\uff1f awaitable\u5bf9\u8c61\u5fc5\u987b\u6ee1\u8db3\u5982\u4e0b\u6761\u4ef6\u4e2d\u5176\u4e2d\u4e4b\u4e00\uff1a
1\u3001A native coroutine object returned from a native coroutine function .
\u539f\u751f\u534f\u7a0b\u5bf9\u8c61
2\u3001A generator-based coroutine object returned from a function decorated with types.coroutine() .
types.coroutine()\u4fee\u9970\u7684\u57fa\u4e8e\u751f\u6210\u5668\u7684\u534f\u7a0b\u5bf9\u8c61\uff0c\u6ce8\u610f\u4e0d\u662fPython3.4\u4e2dasyncio.coroutine
3\u3001An object with an await method returning an iterator.
\u5b9e\u73b0\u4e86await method\uff0c\u5e76\u5728\u5176\u4e2d\u8fd4\u56de\u4e86iterator\u7684\u5bf9\u8c61
\u6839\u636e\u8fd9\u4e9b\u6761\u4ef6\u5b9a\u4e49\uff0c\u6211\u4eec\u53ef\u4ee5\u4fee\u6539\u4ee3\u7801\u5982\u4e0b\uff1a
#!/usr/bin/env python# encoding:utf-8import asyncioimport requestsimport timeasync def download(url): # \u901a\u8fc7async def\u5b9a\u4e49\u7684\u51fd\u6570\u662f\u539f\u751f\u7684\u534f\u7a0b\u5bf9\u8c61response = requests.get(url)print(response.text)async def wait_download(url):await download(url) # \u8fd9\u91ccdownload(url)\u5c31\u662f\u4e00\u4e2a\u539f\u751f\u7684\u534f\u7a0b\u5bf9\u8c61print("get {} data complete.".format(url))async def main():start = time.time()await asyncio.wait([wait_download("http://www.163.com"),wait_download("http://www.mi.com"),wait_download("http://www.google.com")])end = time.time()print("Complete in {} seconds".format(end - start))loop = asyncio.get_event_loop()loop.run_until_complete(main())123456789101112131415161718192021222324252627282930
\u597d\u4e86\u73b0\u5728\u4e00\u4e2a\u771f\u6b63\u7684\u5b9e\u73b0\u4e86\u5f02\u6b65\u7f16\u7a0b\u7684\u5c0f\u7a0b\u5e8f\u7ec8\u4e8e\u8bde\u751f\u4e86\u3002 \u800c\u76ee\u524d\u66f4\u725b\u903c\u7684\u5f02\u6b65\u662f\u4f7f\u7528uvloop\u6216\u8005pyuv\uff0c\u8fd9\u4e24\u4e2a\u6700\u65b0\u7684Python\u5e93\u90fd\u662flibuv\u5b9e\u73b0\u7684\uff0c\u53ef\u4ee5\u63d0\u4f9b\u66f4\u52a0\u9ad8\u6548\u7684event loop\u3002
uvloop\u548cpyuv
pyuv\u5b9e\u73b0\u4e86Python2.x\u548c3.x\uff0c\u4f46\u662f\u8be5\u9879\u76ee\u5728github\u4e0a\u5df2\u7ecf\u8bb8\u4e45\u6ca1\u6709\u66f4\u65b0\u4e86\uff0c\u4e0d\u77e5\u9053\u662f\u5426\u8fd8\u6709\u4eba\u5728\u7ef4\u62a4\u3002 uvloop\u53ea\u5b9e\u73b0\u4e863.x, \u4f46\u662f\u8be5\u9879\u76ee\u5728github\u4e0a\u59cb\u7ec8\u6d3b\u8dc3\u3002
\u5b83\u4eec\u7684\u4f7f\u7528\u4e5f\u975e\u5e38\u7b80\u5355\uff0c\u4ee5uvloop\u4e3a\u4f8b\uff0c\u53ea\u9700\u8981\u6dfb\u52a0\u4ee5\u4e0b\u4ee3\u7801\u5c31\u53ef\u4ee5\u4e86
import asyncioimport uvloopasyncio.set_event_loop_policy(uvloop.EventLoopPolicy())123

关于generator异步编程的理解以及如何动手写一个co模块

generator出现之前,想要实现对异步队列中任务的流程控制,大概有这么一下几种方式:



generator出现之前,想要实现对异步队列中任务的流程控制,大概有这么一下几种方式:

回调函数

事件监听

发布/订阅

promise对象

第一种方式想必大家是最常见的,其代码组织方式如下:

请点击输入图片描述

function fn(url, callback){ var httpRequest;//创建XHR
httpRequest = window.XMLHttpRequest ? new XMLHttpRequest() :
window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : undefined;

httpRequest.onreadystatechange = function(){ if(httpRequest.readystate === 4 && httpRequest.status === 200){//状态判断 callback.call(httpRequest.responseXML);
}
};
httpRequest.open("GET", url);
httpRequest.send();
}
fn("text.xml", function(){//调用函数
console.log(this); //此语句后输出});
console.log("this will run before the above callback.");//此语句先输出

请点击输入图片描述

对于一个普通的ajax异步请求来说,我么在请求开始的时候就要告诉他请求成功之后所要执行的动作,因此就可以类似以这种方式组织代码,控制异步流程。这种调用方式最大的问题就是回调黑洞的问题,一层回调也还好,但涉及到二层、三层、n层的时候就让代码变得复杂很难维护。

第二种方式自己在前段时间使用backbone.js作为技术栈的项目的开发中深有体会,对于每一个ajax请求都对其分配一个自定义事件,在ajax成功返回数据的时候,就会触发自定义的事件完成接下来的动作,控制异步流程,代码如下:

请点击输入图片描述

请点击输入图片描述

第三种方式和第二种的方式性质上有些类似,如果从发布订阅的角度来看,on方法相当于订阅者/观察者,trigger方法相当于发布者。原理上来说无非就是维护一个“消息中心”的数组,通过on方法订阅的事件都会推入“消息中心”数组,最后发布的时候将会匹配“消息中心”数组的事件,进而执行相应的流程。

我们通过jquery的sub/pub插件完成一个很简单的演示。

首先,f2向"信号中心"jQuery订阅"done"信号。

请点击输入图片描述

 jQuery.subscribe("done", f2);
function f1(){

setTimeout(function () {

// f1的任务代码

jQuery.publish("done");

}, 1000);

}

f1();

请点击输入图片描述

jQuery.publish("done")的意思是,f1执行完成后,向"信号中心"jQuery发布"done"信号,从而引发f2的执行。

第四种方式promise范式,先看一段代码:

请点击输入图片描述

我们只要并且仅需要new一个promise对象,就会发现promise对象的参数函数已经执行了,隔两秒之后输出"执行完成"。

接下来再看一段其实际应用的场景代码:

请点击输入图片描述

从本质上来看,Promise是一个构造函数,其本身有all、reject、resolve等方法,同时其原型上有then、catch等方法。通过其用Promise new出来的对象自然就有then、catch方法。然后可以通过then方法中的回调函数,获取到上一段异步操作中返回(通过resolve)的数据。从而实现对异步操作的流程控制。

但我的每个函数都得被promise对象包装一下,同时一大堆的then...真是一个听蛋疼的事儿...

综上所述对于异步流程的控制,都有其自身的缺陷,我们最理想的方式便是像操作同步流程那样实现对异步流程的控制,试想一下这样的异步操作流程(加了层层包装,proxy便是发送一个异步请求,接下来的代码便是获取到异步操作返回的数据,细节可暂时忽略):

请点击输入图片描述

这感觉就是真他妈的舒服,怎么实现这么一个让人很爽的东西呢,于是我们的主角---伟大的Generator函数登场了。

先理解这么自己悟的一句话:

"javascript是单线程的,顺序执行一段代码,执行到了异步操作,按正常的逻辑走的话就是主队列中的代码继续执行,这时异步队列中的代码还未执行,我们继续执行的代码也就会发生报错。那么解决问题的关键就是,我们能够手动控制代码的向下执行,配合一个东西监听到异步操作的已经正常返回了之后,去手动的操作代码的执行流程,这样的话就实现了已同步的方式控制异步代码的执行"

那么问题变成了解决两个问题。

1、我们是如何实现对于异步操作是否成功返回的监听。

2、如何手动操作代码的向下执行。

对于第一个问题,我们采用的方案是使用promise对象的方式,Promise 的编程思想便是,用于“当xx数据准备完毕,then执行xx动作”这样的场景,用在这里再适合不过。

对于第二个问题,我们便是采用伟大的generator生成器函数,其中的yield特性,可以使我们手动的控制代码的向下执行。

接下来我们实际的解决一个问题:实现对于读取文件异步操作的控制,当读取完文件之后打印读取的内容。

我们依赖于node环境,首先通过promise对其进行封装,实现数据成功的监听。我们手下代码如下:

请点击输入图片描述

var fs = require('fs');var readFile = function(fileName) { return new Promise(function(resolve,reject) {
fs.readFile(fileName, function(err, data) { if (err) return reject(err);
resolve(data);
})
})
}

请点击输入图片描述

有了这个东西,我们便可以通过其then()表达式,"当数据加载完后,执行某个动作"。那我们执行的动作是啥,自然就是执行下一步的代码的操作。继续看代码:

请点击输入图片描述

var gen = function* () { var f1 = yield readFile('/Users/dongzhiqiang/Desktop/demo.txt'); var f2 = yield readFile('/Users/dongzhiqiang/Desktop/demo.txt');
console.log('<<<<<<<<<<<<<<<<<<<<<<<',f1.toString());
console.log('>>>>>>>>>>>>>>>>>>>>>>>>',f2.toString());
}

请点击输入图片描述

这个就是一个generator函数的表达式,在这个函数里面,遇到generator就会执行类似于return的操作。我们通过next()便可以实现手动的控制代码的向下执行。

那么我们如何控制代码的执行流程呢,看下面一段:

请点击输入图片描述

var g = gen();
g.next().value.then(function(data){
g.next(data).value.then(function(data){
g.next(data);
});
});

请点击输入图片描述

这段的具体解释就是,我们通过promise封装的对象实现了对于异步操作数据返回的监听,当数据返回的时候,我们就通过next()执行下一步的操作,同时把上步操作的值带入到下一个阶段的执行流程之中。

但是上面这段操作很是蛋疼啊,我们要的是一个能通用的操作流程函数。那么我们继续对这段循环操作进行封装:

请点击输入图片描述

function run(gen){ var g = gen(); function next(data){ var result = g.next(data); if (result.done) return result.value;
result.value.then(function(data){
next(data);
});
}
next();
}
run(gen);

请点击输入图片描述

于是一个非常简单的co模块便诞生了。
最终代码如下:

请点击输入图片描述

我们把函数放到run的执行器里面,便实现了同步操作异步代码的过程。

第一种方式想必大家是最常见的,其代码组织方式如下:

function fn(url, callback){
var httpRequest;    //创建XHR
httpRequest = window.XMLHttpRequest ? new XMLHttpRequest() :  
    window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : undefined;

httpRequest.onreadystatechange = function(){
if(httpRequest.readystate === 4 && httpRequest.status === 200){  //状态判断
callback.call(httpRequest.responseXML);
}
};
httpRequest.open("GET", url);
httpRequest.send();
}

fn("text.xml", function(){    //调用函数
console.log(this);   //此语句后输出
});

console.log("this will run before the above callback.");  //此语句先输出
对于一个普通的ajax异步请求来说,我么在请求开始的时候就要告诉他请求成功之后所要执行的动作,因此就可以类似以这种方式组织代码,控制异步流程。这种调用方式最大的问题就是回调黑洞的问题,一层回调也还好,但涉及到二层、三层、n层的时候就让代码变得复杂很难维护。

第二种方式自己在前段时间使用backbone.js作为技术栈的项目的开发中深有体会,对于每一个ajax请求都对其分配一个自定义事件,在ajax成功返回数据的时候,就会触发自定义的事件完成接下来的动作,控制异步流程,代码如下:

第三种方式和第二种的方式性质上有些类似,如果从发布订阅的角度来看,on方法相当于订阅者/观察者,trigger方法相当于发布者。原理上来说无非就是维护一个“消息中心”的数组,通过on方法订阅的事件都会推入“消息中心”数组,最后发布的时候将会匹配“消息中心”数组的事件,进而执行相应的流程。

我们通过jquery的sub/pub插件完成一个很简单的演示。

首先,f2向"信号中心"jQuery订阅"done"信号。

 jQuery.subscribe("done", f2);
function f1(){

    setTimeout(function () {

      // f1的任务代码

      jQuery.publish("done");

    }, 1000);

  }

f1();

jQuery.publish("done")的意思是,f1执行完成后,向"信号中心"jQuery发布"done"信号,从而引发f2的执行。

第四种方式promise范式,先看一段代码:

我们只要并且仅需要new一个promise对象,就会发现promise对象的参数函数已经执行了,隔两秒之后输出"执行完成"。

接下来再看一段其实际应用的场景代码:

从本质上来看,Promise是一个构造函数,其本身有all、reject、resolve等方法,同时其原型上有then、catch等方法。通过其用Promise new出来的对象自然就有then、catch方法。然后可以通过then方法中的回调函数,获取到上一段异步操作中返回(通过resolve)的数据。从而实现对异步操作的流程控制。

但我的每个函数都得被promise对象包装一下,同时一大堆的then...真是一个听蛋疼的事儿...

综上所述对于异步流程的控制,都有其自身的缺陷,我们最理想的方式便是像操作同步流程那样实现对异步流程的控制,试想一下这样的异步操作流程(加了层层包装,proxy便是发送一个异步请求,接下来的代码便是获取到异步操作返回的数据,细节可暂时忽略):

这感觉就是真他妈的舒服,怎么实现这么一个让人很爽的东西呢,于是我们的主角---伟大的Generator函数登场了。

一直以来,“异步”编程问题一直困扰着广大的 JavaScript 开发者。近年来出现了各种异步解决方案,从基于最原始的callback方式的async函数,到promise标准,再到基于generator的co库,以及即将纳入 ES7 标准的async function / await语法,但是由于各种现实的原因,它们的表现并不尽人意。
原始的callback方式简单明了,不需要过多的依赖,但是在异步逻辑较复杂的场景下写出来的程序并不太直观,就我个人的使用经验而言,尽管多年来已经练就了一身可以穿梭在各种嵌套回调的“乱码”之中,每次重新看这些代码都头疼不已。
JavaScript 异步解决方案都是朝着更直观(跟写同步代码一样)的方向发展的,比如近来呼声最高的async function / await语法,直接从语言层面解决问题,使用体验那是好得没法说的。但是,这是一个 ES7 (ES2017,即明年才会发布的 ES 标准)标准的语法,目前并没有得到各 JavaScript 引擎的内置支持。虽然我们照样可以使用 Babel 神器来将它编译成 ES5 / ES6 的语法,然后运行在现有的 JavaScript 引擎之上。然而使用 Babel 编译后的代码并不易于维护,首先这些代码修改后要先经过一次编译,当我们在生产环境上执行编译后的代码时,很难准确地定位到源码出错的位置。另外,根据最新可靠的消息,Node v7 版本会在语法层面上支持async function / await语法,但该版本原计划于 9 月 30 号发布却跳票了,而且按照往年的惯例,也要在 1 年后发布的 Node v8 LTS 版本上才会正式支持该语法,这对于追求稳定的企业来说还需要一个漫长的等待过程。

Generator 是 ES6 提供的一个新的数据类型,可以叫做 Generator 函数,但跟普通函数又有些不同。

其最大特点就是可以交出函数的执行权(即暂停执行)



  • 瀛︿範Java鐨勬渶浣宠矾绾
    绛旓細鐞嗚В杩愯鍘熺悊鐨勬渶濂芥柟娉曞氨鏄槄璇绘簮浠g爜锛岃繕鏄鎰熻阿Java涓殑寮婧愰」鐩傝繖鏈熼棿杩樿澶氭壘鍚勭澶у皬鐨勯」鐩幓瀹屾垚锛屼笉涓瀹氳澶э紝浣嗘槸瑕佺簿鑷达紝鍔熻兘瑕佸畬鏁达紝杩欐牱鍙互缁冧範鎵瀛︾煡璇嗭紝骞朵笖鍙互鍦ㄥ仛椤圭洰涓彂鐜拌嚜宸辩殑鐭ヨ瘑浣撶郴涓笉瓒崇殑鍦版柟銆鍏充簬鐪嬭棰戯紝鎴戜笉鎺ㄨ崘锛屽緢澶氬悓瀛︿竴澶╁埌鏅氬氨鐭ラ亾鐪嬭棰戯紝娈婁笉鐭ワ紝缂栫▼鐪熺悊鍦ㄤ簬鈥...
  • 澶ф暟鎹煿璁唴瀹,澶ф暟鎹瀛﹀摢浜涜绋
    绛旓細銆婂ぇ鏁版嵁瀹炶璇剧▼璧勬枡銆嬬櫨搴︾綉鐩樿祫婧愬厤璐逛笅杞 閾炬帴:https://pan.baidu.com/s/1RiGvjn2DlL5pPISCG_O0Sw ?pwd=zxcv 鎻愬彇鐮:zxcv 澶ф暟鎹疄璁绋嬭祫鏂檤浜戣绠椾笌铏氭嫙鍖栬绋嬭祫婧恷璇剧▼瀹為獙鎸囧涔︾患鍚堢増|鏈哄櫒瀛︿範涓庣畻娉曞垎鏋愯绋嬭祫婧恷Spark璇剧▼璧勬簮|Python璇剧▼璧勬簮|Hadoop鎶鏈绋嬭祫婧恷浜戣绠楄绋嬭祫鏂.zip|寰....
  • 閭d綅澶уぇ鏁欐垜,53銆67绔彛鍦╟md涓鎬庝箞寮
    绛旓細19 chargen Character Generator 瀛楃鍙戠敓鍣 20 ftp-data File Transfer [Default Data] 鏂囦欢浼犺緭鍗忚(...62 acas ACA Services 寮傛閫 63 whois+ whois+ WHOIS+ 64 covia Communications Integrator (CI)...86 mfcobol Micro Focus Cobol Micro Focus Cobol缂栫▼璇█ 87 ? any private terminal link 棰勭暀缁...
  • 扩展阅读:generator生成器 ... js generator ... ai智能写作一键生成 ... python generator ... petpet generator中文版 ... generator免费合成器 ... 文件管理找不到storage ... 安卓手机storage在哪里 ... 文件下载到storage怎么找 ...

    本站交流只代表网友个人观点,与本站立场无关
    欢迎反馈与建议,请联系电邮
    2024© 车视网