文档章节

JS:异步

xmqywx
 xmqywx
发布于 08/20 02:25
字数 2003
阅读 47
收藏 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
粉丝 8
博文 22
码字总数 7166
作品 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是单线程的深入分析

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

stone_
2014/04/15
0
0
JavaScript可否多线程? 深入理解JavaScript定时机制

JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如 setTimeout( function(){ alert(’你好...

李长春
2012/11/09
0
0
JavaScript定时机制setTimeout与setInterval研究

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

西西爱OS
2012/10/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

00.编译OpenJDK-8u40的整个过程

前言 历经2天的折腾总算把OpenJDK给编译成功了,要说为啥搞这个,还得从面试说起,最近出去面试经常被问到JVM的相关东西,总感觉自己以前学的太浅薄,所以回来就打算深入学习,目标把《深入理...

凌晨一点
今天
4
0
python: 一些关于元组的碎碎念

初始化元组的时候,尤其是元组里面只有一个元素的时候,会出现一些很蛋疼的情况: def checkContentAndType(obj): print(obj) print(type(obj))if __name__=="__main__": tu...

Oh_really
昨天
6
2
jvm crash分析工具

介绍一款非常好用的jvm crash分析工具,当jvm挂掉时,会产生hs_err_pid.log。里面记录了jvm当时的运行状态以及错误信息,但是内容量比较庞大,不好分析。所以我们要借助工具来帮我们。 Cras...

xpbob
昨天
120
0
Qt编写自定义控件属性设计器

以前做.NET开发中,.NET直接就集成了属性设计器,VS不愧是宇宙第一IDE,你能够想到的都给你封装好了,用起来不要太爽!因为项目需要自从全面转Qt开发已经6年有余,在工业控制领域,有一些应用...

飞扬青云
昨天
4
0
我为什么用GO语言来做区块链?

Go语言现在常常被用来做去中心化系统(decentralised system)。其他类型的公司也都把Go用在产品的核心模块中,并且它在网站开发中也占据了一席之地。 我们在决定做Karachain的时候,考量(b...

HiBlock
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部