javaScript 中的异步编程
javaScript 中的异步编程
- 回调函数
- 事件监听
- 发布/订阅
- promise模式
function fn1(){var arr=[];var result;//模拟耗时的任务;for(let i=0;i<100000;i++){for(let j=0;j<100000;j++){result+=j;}}arr.push(new Array(10000).join('*'));console.log("fn1 task has done"); } function fn2(){console.log("fn2 task has done"); }fn1(); fn2();
用setTimeout和回调函数来进行“异步”
//匿名函数 ,闭包,没有了return 和 throw exception的特性滴啊 function fn1(Callback){setTimeout(function() {var arr=[];var result;//模拟耗时的任务;for(let i=0;i<100000;i++){for(let j=0;j<100000;j++){result+=j;}}arr.push(new Array(10000).join('*'));console.log("fn1 task has done");Callback();}, 1000);} //采用这种方式,我们把同步操作变成了异步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行 function fn2(){console.log("fn2 has done.."); }fn1(fn2); console.log("mian line has done..");//这种方式仅仅是防止堵塞fn2的执行,和主线层的执行,。。。。还算不得真正的异步;
总结,第一种做法,堵塞fn2的执行和主线程的执行;
第二种,没堵塞主线程的执行,fn2成为fn1,的回调函数,执行完之后,再执行fn2;
问,如果主线程也遇到一个堵塞操作呢;? 那就要看事件的注册顺序了!因为js的执行是单线程的,如果是多线程的话,
就会出现交替输出的效果;
如果,我们将代码改着下面这样;
function fn1(Callback){setTimeout(function() {var arr=[];var result;//模拟耗时的任务;for(let i=0;i<100000;i++){for(let j=0;j<100000;j++){console.log(j);}} //arr.push(new Array(10000).join('*'));console.log("fn1 task has done");Callback();}, 1000);} //采用这种方式,我们把同步操作变成了异步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行 function fn2(){console.log("fn2 has done.."); }fn1(fn2); console.log("mian line has done..");while(true){console.log("......."); }
控制台中一直输出:.......;
js的特点之一:单线程,
缺点:
回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,
各个部分之间高度耦合(Coupling),流程会很混乱,
而且每个任务只能指定一个回调函数。
事件监听,
第二种,就是采用事件驱动的模式;任务的执行不取决于
另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
我们用node中的事件为示例,node中是出名的基于事件驱动的。
// 引入 events 模块 var events = require('events'); // 创建 eventEmitter 对象 var eventEmitter = new events.EventEmitter();function f2(){console.log("f2 has done..."); }// 绑定事件及事件的处理程序 eventEmitter.on('someEvent', f2);function fn1(){//继续我们的耗时任务;var result;for(let i=0;i<100000;i++){for(let j=0;j<100000;j++){result+=j;}}console.log("fn1 task has done");//触发事件;eventEmitter.emit("someEvent"); } fn1(); console.log("main line has done...");
这种方法的优点是比较容易理解,
可以绑定多个事件,每个事件可以指定多个回调函数,
而且可以"去耦合"(Decoupling),
有利于实现模块化。缺点是整个程序都要变成事件驱动型,
运行流程会变得很不清晰。
上一段代码的"事件",完全可以理解成"信号"。
ps:
Nginx跟Node.js都不是基于多线程模型的,
因为线程跟进程都需要非常大的内存开销。
他们都是单线程的,但是基于事件的。
这种基于单线程的模型消除了为了处理很多请求而创建成百上千个线程或进程带来的开销。
这里不得不用聊一聊我们的基于事件的编程的模式,或者叫publish 和subscribe 的;
发布/订阅(PUB/SUB)是一种消息模式,它有两个参与者:发布者和订阅者。
发布者向某个信道(channel)发布一条消息,
订阅者绑定这个信道,
当有消息发布至信道时就会接受到一个通知。
最重要的一点是,发布者和订阅者是完全解耦的,
彼此并不知道对方的存在。
两者仅仅共享一个信道的名称。
发布者和订阅者的解耦可以让你的运用易于拓展
var PS={//订阅者角色;subscribe :function (ev,callBack){//创建_callback对象,除非它已经存在。var calls=this._callBack || (this._callBack={});/** 针对给定的事件ev创建一个数组,除非这个数组已经存在* 然后调用函数追加到这个数组中* */(this._callBack[ev] || (this._callBack[ev]=[]).push(callBack))return this;},//发布者角色;publish:function (){//将arguments对象转换成为真正的数组var args=Array.prototype.slice.call(arguments,0);//取出第一个参数,就是我们的事件名滴呀;var evName=args.shift();/** 如果不存在_callback对象,则返回* 或者如果不包含给定事件对应的数组**/var list,calls,i,l;if(!(calls=this._callBack)) return this;if(!(list=this._callBack[ev]))return this;//循环触发我们的回调事件;for(let i=0,l=list.length;li<l;i++){list[i].apply(this,args);}return this;} };//订阅感兴趣的东东; PS.subscribe("life",function (){// 回调.... })PS.publish("life");
对了,注意到没有,上面的代码,没有取消事件的方法,我靠;,接下来,我们看一个完整的代码;
function SourceCribe () {// 生成发布/订阅器DOM节点var body = document.querySelector('body');if (!document.querySelector('.magazine')) {var element = document.createElement('mark');element.setAttribute("class", "magazine");body.appendChild(element);}this.magazine = document.querySelector('.magazine');// 消息发布实现this.publish = function (source, data) {if (!typeof source === 'string') {return false;}var oEvent = new CustomEvent(source, {bubbles: true,cancelable: false,detail:data});this.magazine.dispatchEvent(oEvent);};// 订阅实现,handler需要使用显式声明函数,不要使用匿名函数this.subscribe = function (source, handler) {if(!typeof source === 'string' || !typeof value === 'function') {return false;}this.magazine.addEventListener(source, handler, false);};// 取消订阅this.unsubcribe = function (source, handler) {if(!typeof source === 'string' || !typeof value === 'function') {return false;}this.magazine.removeEventListener(source, handler, false);};}(function(window){window.addEventListener('load',function(evt){var sourceCribe = new SourceCribe();var loveHandlerAlways = function (evt) {console.log("always " + evt.detail);};var loveHandlerEver = function (evt) {console.log("ever " + evt.detail);};sourceCribe.subscribe('love', loveHandlerAlways);sourceCribe.subscribe('love', loveHandlerEver);sourceCribe.publish('love','500 days with summer');sourceCribe.unsubcribe('love', loveHandlerAlways);sourceCribe.publish('love','500 days with summer');});})(window)
最后,我们推荐一款,非常简单,并且,牛逼的事件订阅插件的,效果是非常好得呀;
(function($) {var o = $({});$.subscribe = function() {o.on.apply(o, arguments);};$.unsubscribe = function() {o.off.apply(o, arguments);};$.publish = function() {o.trigger.apply(o, arguments);};}(jQuery));
我靠,好像有点侧偏了,明明再说或JavaScript中的异步编程,却扯到我们的额事件上去,不过,我们在学习node,深入理解一下,基于事件的编程是非常完美;
接下来,我们就要将这个发布/订阅 模式了,是基于上面这个框架滴呀;
//这里还有更详尽的文章:https://msdn.microsoft.com/en-us/magazine/hh201955.aspx
function f2(){console.log("f2 has done..."); } jQuery.subscribe("done", f2);function f1(){setTimeout(function () {// f1的任务代码jQuery.publish("done");}, 1000);}// jQuery.publish("done")的意思是,f1执行完成后,向"信号中心"jQuery发布"done"信号,从而引发f2的执行。 // 此外,f2完成执行后,也可以取消订阅(unsubscribe)。 //jQuery.unsubscribe("done", f2); //这种方法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心", //了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
//最后,就是我们的promise对象了滴呀;
https://segmentfault.com/a/1190000003028634
它还有一个前面三种方法都没有的好处:如果一个任务已经完成,再添加回调函数,该回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号
http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html
https://segmentfault.com/a/1190000003028634
转载于:https://www.cnblogs.com/mc67/p/7062094.html
javaScript 中的异步编程相关推荐
- javascript中的异步编程
正常情况下js都是顺序执行的,但是也有很多场景下实际上是异步操作: 1.定时器都是异步操作 2.事件绑定都是异步操作 3.AJAX中一般我们都采取异步操作(也可以同步) 4.回调函数可以理解为异步(不 ...
- JavaScript中的异步梳理(0)
JavaScript中有大量异步操作,首先可以看看JS中什么东西会产生异步(这里先只考虑浏览器里的情况): Ajax(XMLHttpRequest) Image Tag,Script Tag,ifra ...
- JavaScript 中的函数式编程实践
为什么80%的码农都做不了架构师?>>> 基础知识 函数式编程简介 说到函数式编程,人们的第一印象往往是其学院派,晦涩难懂,大概只有那些蓬头散发,不修边幅,甚至有些神经质的大学 ...
- 一文说通C#中的异步编程补遗
前文写了关于C#中的异步编程.后台有无数人在讨论,很多人把异步和多线程混了. 文章在这儿:一文说通C#中的异步编程 所以,本文从体系的角度,再写一下这个异步编程. 一.C#中的异步编程演变 1. ...
- 一文说通C#中的异步编程
天天写,不一定就明白. 又及,前两天看了一个关于同步方法中调用异步方法的文章,里面有些概念不太正确,所以整理了这个文章. 一.同步和异步. 先说同步. 同步概念大家都很熟悉.在异步概念出来之前,我 ...
- 【转】.Net中的异步编程总结
一直以来很想梳理下我在开发过程中使用异步编程的心得和体会,但是由于我是APM异步编程模式的死忠,当TAP模式和TPL模式出现的时候我并未真正的去接纳这两种模式,所以导致我一直没有花太多心思去整理这两部 ...
- 了解和使用DotNetCore和Blazor中的异步编程
目录 介绍 您对异步编程了解什么? 那么,什么是异步编程? 我们什么时候应该使用它? 任务.线程.计划.上下文 到底是怎么回事? Asnyc编码模式 命名约定 异步任务模式 任务模式 事件模式 阻塞与 ...
- .NET中的异步编程——常见的错误和最佳实践
目录 背景 async void 没有线程 Foreach和属性 始终异步 在这篇文章中,我们将通过使用异步编程的一些最常见的错误来给你们一些参考. 背景 在之前的文章中,我们开始分析.NET世界中的 ...
- JavaScript中的异步、同步
要理解JS中的异步.同步,需要先了解JS代码的执行过程和Event Loop. JavaScript代码的执行过程 程序需要执行的操作都会被放入Call Stack(A LIFO (Last In, ...
- JavaScript中的元编程
紧接上回,伴随着Reflect,Proxy降世,为js带来了更便捷的元编程! 什么是元编程?这词第一次听,有点懵,好像有点高级,这不得学一下装-进自己的知识库 概念 元编程是一种编程技术,编写出来的计 ...
最新文章
- cv2.calcOpticalFlowFarneback integer argument expected, got float
- XBodhi(技术框架)——序
- java连接腾讯云上的redis
- C++ 学习路线推荐
- SAP UI5 Web Component里如何自定义CSS style
- 动手造轮子:基于 Redis 实现 EventBus
- linux路由内核实现分析(四)---路由缓存机制(2)
- 确保移动设备的安全:在保护数据的同时提高工作效率
- 分布式服务框架-原理与实践:15---服务降级-学习笔记
- 10年腾讯技术专家有话对你说
- 如何安装.net framework?Win11安装net framework的方法
- python爬取豆瓣小组_Python爬虫实战(4):豆瓣小组话题数据采集—动态网页
- 三线表里加小短线_快速搞定学术论文中的三线表
- nmake、makefile、cmake学习笔记
- 关于Lua的下载以及wlua、luac等文件的解释
- CnOpenData中国行政区划数据简介
- npm ERR! This is probably not a problem with npm. There is likely additional log ging output above.
- 计算机软考最佳时间,软考报名时间是什么时候?软考有哪些意义?
- 北京医保卡怎么使用?
- 如何正确选择集体渲染(云渲染)和gpu离线渲染