使用Java编写的应用, 可以编程开启多线程处理高并发业务场景.
而JS处理高并发场景使用的是 : 队列机制, 事件机制
因为JS在网页中运行时单线程模式, 在服务端nodejs中运行是单进程模式, 都无法像JAVA那样开启多个线程或者协程来处理高并发任务.
但是这不意味着JS无法处理高并发任务, 单进程的程序在使用队列机制(就是待处理任务一个个排队)处理高并发场景也仍然是非常高效的, 而且避免了开启多个线程的内存消耗.但是其缺点也是很明显的 : 不适合处理单个任务计算非常复杂消耗时间的场景.
举个栗子 :
想象一下生活中排队的场景, 如果前面有一个人磨磨唧唧, 半天赖在窗口各种问问题, 后面的人都要排队等着, 很着急.
而如果开启多个窗口(多线程/进程), 那些难缠的人分到一个窗口, 速度快的人分到一个窗口, 效率就大大提升了.
总结:yield修饰符具有中断性,将yield后面的数据返回,同时具有恢复现场的特性,再次进入可以携带数据,同时返回下一个yield后面数据,当迭代完毕,返回一个value为空的数据。done被置为true.
那么利用这个特性,可以实现异步流程同步化。
思路:迭代器的next我们可以理解为一次请求,我们在当前请求的回调里实现迭代器的下一个next,这样异步流程就能实现顺序执行。
1 .首先我们一个参数是回调的方法,这样在异步耗时操作之后可以调用这个回调,进而进行下一次的next调用。**
2 .然后我们需要把多个异步请求的流程写下来(其实就是生成器),比如1,2,3,4四个请求顺序执行,
3. 有了生成器步骤,那么接下来我们就可以用迭代器next来实现顺序执行:
4. 调用:
直接上源码:
可以看出 四个模拟的网络请求请求时间不同,但是执行顺序按照了我们规定的顺序执行。
至于后面我们常用的async/await用法其实跟这个差不多。只不过是经过了一层包装,让外部行为看起来比较统一。经过async修饰过方法会被包装成promise对象,这跟我们的上面的 mockReq 其实大同小异,然后再网络请求的回调里执行resolve/ reject(其实就是上面的callBack).当然promise功能还有很多,我们只是讨论模仿async/await相关问题。
经过上面的描述,我们已经知道js的协程相关特性,但是iOS没有协程相关的方法,没有yield,没有async /await.我们想一下,yield主要作用是什么呢? 中断 + 恢复 现场的功能。虽然iOS没有这些,但是想一下GCD里面的信号量semaphore也具有中断特性(semaphore的数量为0,执行wait(Forever)就会中断当前线程),我们先开启一个异步任务,然后执行多个任务的主队列使用信号量进行中断,然后在单个的异步任务队列的回调里重新使信号量加一,从而恢复主任务队列,然后执行下一个子任务,依次类推。
那思路已经有了,其实就是把js里的yield换成了semaphore.涉及到任务队列,信号量,异步任务,我们可以用一个对象来关联他们,保证任务队列和异步任务里的信号量是同一个,但是对象在方法栈里生成,在方法栈结束时会被释放,这时异步任务可能还没有回来,此时就需要一个全局的dic来持有,通过barrier监听主任务队列,等到任务队列里的所有任务都执行完毕之后,将这个管理对象释放掉:
talk is cheap,show me the code
用法
我们要使用分两步:
第一步:需要构造一个 JTWaitClosure 类型的block。如上面的的请求百度、必应。
第二步:在 JT_AsyncOperation 的async方法的block中,使用JT_AWAIT('任务')的形式,来实现类似async/await的用法。
使用JT_AsyncOperation 的async/await的优点:
需要注意的事情:因为主任务队列是异步并发,所以在更新UI相关的操作,需要切换到主线程。