文档章节

JS:异步

xmqywx
 xmqywx
发布于 08/20 02:25
字数 2003
阅读 74
收藏 0

工作这几年,最近才有了新的想法还认识,我应该做出一些改变,去慢慢深入思考一些问题,本文是我第一个小小的开始。

单线程

javascript是单线程的,同步的。为什么JS是单线程的?

Javascript是个脚本语言,是在客户端,为了控制界面显示用的。所以不可能准许两个线程同时影响页面渲染同一个组件这种事件发生。 PS:我们平常最近工作用的web worker:是在Javascript单线程执行的基础上,开启一个子线程,进行程序处理,而不影响主线程的执行。web worker是不参与页面渲染工作的。

EventLoop

他是JS 实现异步的具体解决方案。

主进程:同步代码。

异步队列:所有的异步函数都会放在异步队列中。等待同步函数执行完成,轮询执行异步队列函数,异步队列函数这个时候有的需要执行的话直接放在主进程中执行,执行结束继续监听轮询异步队列。

	// 两种形式的异步
	// 1. setTimeout(),time是否为零其实都是异步操作,都会加到event queue中去。
	//PS:HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为10毫秒。另外,对于那些DOM的变动(尤其是涉及页面重新渲染的部分),通常不会立即执行,而是每16毫秒执行一次。这时使用requestAnimationFrame()的效果要好于setTimeout()。
			setTimeout(() => {}, time);
	// 2.异步操作。如promise,fileload, XMLHttpRequest

首先主进程调用的是堆栈。但是异步函数并没有在这个堆栈中。

每次setTimeout 或者 异步请求发生,都会添加到Event Table里,一旦发生timeout,click等事件,就会将他跟踪的事件发送给事件队列。事件队列是类似堆栈的数据结构。事件队列到达call stack过程就是event loop发挥的作用。它是一直执行的进程,检查call stack是否为空,为空就检查event queue, 有的话添加到call stack。

题外话,工作中使用递归,报错堆栈溢出。为满足某种必要的需求,我们必须使用递归的时候,加了setTimeout就可以了。PS:虽然这不是什么好方法。所以,为什么之前我们这么写不溢出了,是不是这里有了答案。

Promise

jQuery Deferred

jQuery 你妹的过去天天用:),但是你知道Jquery Deferred吗。

jQuery 1.5之后对Ajax 进行了重写。可以then了。。。链式结构的书写一直是jQuery的一大亮点,不再一步步的callback,总让你感觉到科学多了,置于后面每次我们封装的时候,都希望避免层层调用的代码习惯。

	 function ajaxFun() {
			let defer = $.Deferred()
			let asyncFun = function (dtd) {
				setTimeout(() => {
					defer.resolve()
					// error
					// defer.reject()
				}, 1000)
				// wait 返回
				return defer.promise()
			}
			return asyncFun(defer)
		}

可以看到,jQuery 已经有了promise的概念。我不知道这是不是ES6 promise 的起源所在。最后之所以返回defer.promise而不是defer,是因为defer 本身有resolve done reject always 等方法,可以在函数外边进行触发,不符合开放封闭原则。deferred使用promise之后只能调用done 和 fail。

ES6 promise

工作中我们经常的使用promise封装,但是真正的被深入去问的话,还是挺尴尬的。

先去看一眼阮一峰的文档 http://es6.ruanyifeng.com/#docs/promise

关于promise 串联,工作中经常也会用到,then 函数里面要返回下一个promise实例,假如没有return 默认返回自己。

Fetch

手机端我们经常用到fetch,虽然他在这个web端有兼容性的问题,其实用一些插件都可以解决。但是目前应用已经很广泛了。 fetch不同于XMLHttpRequest。fetch是基于Promise设计的,具有promise的优点,也有promise的缺点。

  1. fetch默认不携带cookie,需要配置credentials
  2. 不支持progress事件, 当然网上有很多解决办法。
  3. fetch支持类外一种cors的跨域,在mode中配置no-cors,配合ServiceWorker使用.
  4. 服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。

Axios

Axios本质上是对原生XHR的封装,它是Promise的实现版本。用起来所以和fetch 有本质的区别。但相比较比Fetch 用户体验强多啦。从写法,headr配置,拦截器,request的body,到response,都省不少力气。 写代码得爽为标准,应用层级上还是axios 合得来胃口。

Async/Await

Async [ə'zɪŋk]嗯,先学一下音标。 自从ES7提出来,项目中也一直使用,使用完全同步的写法,感觉这代码又美观了许多。Callback 又再次被击退了一步。

promise reject 时依然会返回,所以await要使用try catch 捕获异常。基于这种情况我们可以对axios使用async/await 进行二次封装,以便让我们代码更直观。

redux-saga

React和Vue 可以说是整天用了,其中有个插件redux-saga,当时我真的挺感兴趣,曾经一晚上开了荒,第二天被邀请去一家公司讲解(去误人子弟)。

他使用了区别于async的一种解决方式,而async被称为是对Generator有自身的改进。saga 则使用了Generator本身实现了异步的处理。在异步的过程中是可以控制管理的,多个异步请求运行都是清晰可见的,对于测试调试是一大进步。

Saga可以看成一个一直在不断执行Generator 里面 next() 的线程。

// saga.js

function* mySaga(){
	...action 触发
	const data = yield call(GET, 'xxxx/api/getdata');
	yield put(SHOW_DATA_ACTION, {data: data});
}

当一开始action未触发时,是被阻塞的,当saga 里take到了action,继续执行, 当发生promise 时,线程会再次被挂起,promise resolve后,线程继续运行。而这个不断next的过程是saga自己一开始项目启动一直运行的,通过这个原理实现了异步阻塞然后再运行的效果。从何时阻塞,何时开始下一步都是清晰可见的。

Async.js

曾经一个好友介绍给我的插件

他提供了出了流程控制(串行,并行,瀑布流)解决方案。里面可以解决一些异步操作带来的难题。

他可以配合使用ES7的async/await,

	async.mapLimit(urls, 5, async function(url) {
		const response = await fetch(url)
		return response.body
	}, (err, results) => {
		if (err) throw err
		// results is now an array of the response bodies
		console.log(results)
	})

一些流程控制,我们并非需要全部都封装成promise使用,在实际应用中Async.js 虽然是node.js的框架,也能在客户端使用,我们使用它会使我们的工作更快捷。ES7 async/await 同样带给我们的一些断点调试的困扰,无法直观的体现业务流程过程,选择合理的方式也是工作的关键。

总结

文章并没有提到具体某个东西怎么用,promise怎么写,jquery怎么写,或者axios怎么用,非常抱歉。因为网上说的太多了,各种文章也是一坨一坨的。我也只是了解一下异步,但对于一个实用主义的我来说,确是高兴不起来。暂时写这么一点,以后继续研究。留下一些疑问1.call stack的执行方式 2.chrome中调试call stack

© 著作权归作者所有

共有 人打赏支持
xmqywx
粉丝 10
博文 25
码字总数 8772
作品 0
青岛
程序员
私信 提问
Javascript是单线程的深入分析

面试的时候发现99%的童鞋不理解为什么JavaScript是单线程的却能让AJAX异步发送和回调请求,还有setTimeout也看起来像是多线程的?还有non-blocking IO, event loop等概念很不清楚。来深入分析...

stone_
2014/04/15
0
0
Javascript 异步加载详解

一、同步加载与异步加载的形式 1. 同步加载 我们平时最常使用的就是这种同步加载形式: <script src="http://yourdomain.com/script.js"></script> 同步模式,又称阻塞模式,会阻止浏览器的后...

Carl_
2014/09/15
0
0
Javascript 异步加载详解

一、同步加载与异步加载的形式 1. 同步加载 我们平时最常使用的就是这种同步加载形式: <script src="http://yourdomain.com/script.js"></script> 同步模式,又称阻塞模式,会阻止浏览器的后...

张悟空
2014/08/18
0
0
总结:JavaScript异步、事件循环与消息队列、微任务与宏任务

前言 Philip Roberts 在演讲 great talk at JSConf on the event loop 中说:要是用一句话来形容 JavaScript,我可能会这样: “JavaScript 是单线程、异步、非阻塞、解释型脚本语言。” 单线...

正伟_
昨天
0
0
JavaScript定时机制setTimeout与setInterval研究

容易欺骗别人感情的JavaScript定时器 本文转自:爱微网 JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都...

西西爱OS
2012/10/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

mysql导入较大的数据文件

mysql一次导入较大的sql文件的时候会出现导入的瓶颈,用工具例如sqlyog之类的执行几十M都不行了,直接报内存不足,看来去服务器上执行sql命令才是王道。 服务器上执行有两种思路: 以Linux命...

sensy
3分钟前
0
0
Redis 基础入门

为什么需要Redis 传统的关系数据库MySQL,ORacle等的数据主要还是存储在磁盘上,虽然数据库各自都带有缓存功能,但随着业务量的增大,数据库自身的缓存终将成为瓶颈,次数如果要提供应用的效...

PeakFang-BOK
4分钟前
0
0
VS2017设置“编辑并继续”无效的问题

设置“编辑并继续” 在“工具”菜单上,单击“选项”。 在“选项”对话框中,打开“调试”节点,然后选择“编辑并继续”类别。 若要启用它,请选中“启用‘编辑并继续’”复选框。 若要禁用它...

随你疯
16分钟前
0
0
(5)添加svg支持

(5)添加svg支持 1 安装svg-sprite-loader cnpm install svg-sprite-loader --save svg-sprite-loader是一个webpack loader,可以将多个svg打包成svg-sprite。 2 配置svg-sprite-loader 我们......

neumeng
16分钟前
0
0
17-《深度拆解JVM》之即时编译(上)

一、问题引入 在第一篇中,我们简单了解过即时编译。这是一项用来提升应用程序运行效率的技术。通常而言,代码会先被 Java 虚拟机解释执行,之后反复执行的热点代码则会被即时编译成为机器码...

飞鱼说编程
34分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部