文档章节

JS:异步

xmqywx
 xmqywx
发布于 2018/08/20 02:25
字数 2003
阅读 78
收藏 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
粉丝 12
博文 25
码字总数 8772
作品 0
青岛
程序员
私信 提问
Javascript是单线程的深入分析

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

stone_
2014/04/15
0
0
JavaScript定时机制setTimeout与setInterval研究

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

西西爱OS
2012/10/25
0
0
『前端干货篇』: 你不知道的Event Loop

一星期的满课,身心疲惫(×_×)...周末闲下来,仔细研究了下JS的事件轮询机制,看了看阮一峰大大的相关文章,真的收货挺多。 从一道面试题说起 相信这道题很多人都看过,结果是先输出,再输出...

酱菜豪
2018/10/30
0
0
异步加载script,提高前端性能(defer和async属性的区别)

一、异步加载script的好处 为了加快首屏响应速度,前端会采用代码切割、按需加载等方式优化性能。异步加载script也是一种前端优化的手段。 就好比如果我的页面其中一个功能需要打开地图,但是地...

xiaobe
2018/08/22
0
0
JavaScript可否多线程? 深入理解JavaScript定时机制

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

李长春
2012/11/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

c++ 定义新的异常

#include <iostream> #include <exception> using namespace std; struct MyException : public exception { const char * what () const throw () { return "C++ Exception"; } }; int main......

天王盖地虎626
今天
3
0
PDMan-2.1.1 发布:用心开源,免费的国产数据库建模工具(春节前最后一个版本)

一、软件介绍 PDMan 是一款开源免费的数据库模型建模工具,是PowerDesigner之外另一种更好的选择。支持Windows,Mac,Linux等操作系统,具有上手容易,使用简单的特点。 2018年获得码云GVP (Gi...

O龙猫O
今天
18
0
OSChina 周二乱弹 —— 以后我偷小鱼干养你

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @庞巴哥 :只有这节奏瞬间变得轻松。。。。。。。。。分享Talking Eyes的单曲《In the sun (Extended Version)》: 《In the sun (Extended Ve...

小小编辑
今天
547
10
多表查询

第1章 多表关系实战 1.1 实战1:省和市  方案1:多张表,一对多  方案2:一张表,自关联一对多 1.2 实战2:用户和角色 (比如演员和扮演人物)  多对多关系 1.3 实战3:角色和权限 (比如...

stars永恒
今天
9
0
求推广,德邦快递坑人!!!!

完全没想好怎么来吐槽自己这次苦逼的德邦物流过程了,只好来记一个流水账。 从寄快递开始: 2019年1月15日从 德邦物流 微信小app上下单,截图如下: 可笑的是什么,我预约的是17号上门收件,...

o0无忧亦无怖
昨天
14
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部