Promise-js中的同步和异步
js中的同步和异步
自从读了研后,走上了学术之路,每天除了看论文就是做实验,最后发现自己还是喜欢开发呀,于是我又重回前端啦~
隔了这么久没学前端,好像很多东西都忘了不少,而且不得不说前端的技术更新是真的快,接下来将会重新拾起前端的一点一滴,首先进入的是js的同步和异步的世界~
一、单线程
(1)单线程的概念
如果大家熟悉java,应该都知道,java是一门多线程语言,我们常常可以利用java的多线程处理各种各样的事,比如说文件上传,下载等,而JavaScript是否也可以支持多线程呢?
答案是否定的,JavaScript是一门单线程的语言,因此,JavaScript在同一个时间只能做一件事,单线程意味着,如果在同个时间有多个任务的话,这些任务就需要进行排队,前一个任务执行完,才会执行下一个任务,比如说下面这段代码

// 同步代码
function fun1() {
console.log(1);
}
function fun2() {
console.log(2);
}
fun1();
fun2(); // 输出
1
2

很容易可以看出,输出会依次输入1,2,因为代码是从上到下依次执行,执行完fun1(),才继续执行fun2(),但是如果fun1()中的代码执行的是读取文件或者ajax操作,文件的读取和数据的获取都需要一定时间,难道我们需要完全等到fun1()执行完才能继续执行fun2()么?为了解决这个问题,后面我们会介绍同步和异步的概念
(2)为什么是单线程
其实,JavaScript的单线程,与它的用途是有很大关系,我们都知道,JavaScript作为浏览器的脚本语言,主要用来实现与用户的交互,利用JavaScript,我们可以实现对DOM的各种各样的操作,如果JavaScript是多线程的话,一个线程在一个DOM节点中增加内容,另一个线程要删除这个DOM节点,那么这个DOM节点究竟是要增加内容还是删除呢?这会带来很复杂的同步问题,因此,JavaScript是单线程的
二、同步任务和异步任务
(1)为什么会有同步和异步
因为JavaScript的单线程,因此同个时间只能处理同个任务,所有任务都需要排队,前一个任务执行完,才能继续执行下一个任务,但是,如果前一个任务的执行时间很长,比如文件的读取操作或ajax操作,后一个任务就不得不等着,拿ajax来说,当用户向后台获取大量的数据时,不得不等到所有数据都获取完毕才能进行下一步操作,用户只能在那里干等着,严重影响用户体验
因此,JavaScript在设计的时候,就已经考虑到这个问题,主线程可以完全不用等待文件的读取完毕或ajax的加载成功,可以先挂起处于等待中的任务,先运行排在后面的任务,等到文件的读取或ajax有了结果后,再回过头执行挂起的任务,因此,任务就可以分为同步任务和异步任务
(2)同步任务
同步任务是指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务,当我们打开网站时,网站的渲染过程,比如元素的渲染,其实就是一个同步任务
(3)异步任务
异步任务是指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,当我们打开网站时,像图片的加载,音乐的加载,其实就是一个异步任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
function fun1() { console.log(1); } function fun2() { console.log(2); } function fun3() { console.log(3); } fun1(); setTimeout( function (){ fun2(); },0); fun3(); // 输出 1 3 2 |
有了异步,就算fun2()里面是文件的读取或ajax这种需要耗时的任务,也不怕fun3()要等到fun2()执行完才能执行啦
(4)异步机制
那么,JavaScript中的异步是怎么实现的呢?那要需要说下回调和事件循环这两个概念啦
首先要先说下任务队列,我们在前面也介绍了,异步任务是不会进入主线程,而是会先进入任务队列,任务队列其实是一个先进先出的数据结构,也是一个事件队列,比如说文件读取操作,因为这是一个异步任务,因此该任务会被添加到任务队列中,等到IO完成后,就会在任务队列中添加一个事件,表示异步任务完成啦,可以进入执行栈啦~但是这时候呀,主线程不一定有空,当主线程处理完其它任务有空时,就会读取任务队列,读取里面有哪些事件,排在前面的事件会被优先进行处理,如果该任务指定了回调函数,那么主线程在处理该事件时,就会执行回调函数中的代码,也就是执行异步任务啦
单线程从从任务队列中读取任务是不断循环的,每次栈被清空后,都会在任务队列中读取新的任务,如果没有任务,就会等到,直到有新的任务,这就叫做任务循环,因为每个任务都是由一个事件触发的,因此也叫作事件循环
总的来说,JavaScript的异步机制包括以下几个步骤
(1)所有同步任务都在主线程上执行,行成一个执行栈
(2)主线程之外,还存在一个任务队列,只要异步任务有了结果,就会在任务队列中放置一个事件
(3)一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面还有哪些事件,那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行
(4)主线程不断的重复上面的第三步
三、异步编程
那么,怎么才能实现异步编程,写出性能更好的代码呢,下面有几种方式
(1)回调函数
回调函数是实现异步编程最简单的方法啦,回调函数我们在使用ajax时应该用的很多啦,其实在使用ajax时,我们就用到了异步
1
2
3
4
|
var req = new XMLHttpRequest(); req.open( "GET" ,url); req.send( null ); req.onreadystatechange= function (){} |
req.send()方法是 AJAX 向服务器发生数据,它是一个异步任务,而 req.onreadystatechange()属于事件回调,借由浏览器的HTTP请求线程发起对服务器的请求,在请求得到响应之后触发请求完成事件,将回调函数推入事件队列等待执行
其实像setTimeout,还有我们平时为元素绑定监听事件,和上面说的道理也是一样的
回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数
(2)Promise
一直以来,JavaScript处理异步都是以callback的方式,在前端开发领域callback机制几乎深入人心,近几年随着JavaScript开发模式的逐渐成熟,CommonJS规范顺势而生,其中就包括提出了Promise规范,Promise完全改变了js异步编程的写法,让异步编程变得十分的易于理解,同时Promise也已经纳入了ES6,而且高版本的chrome、firefox浏览器都已经原生实现了Promise,只不过和现如今流行的类Promise类库相比少些API
Promise包括以下几个规范
- 一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)
- 一个promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换,同时“完成”态和“拒绝”态不能相互转换
- promise必须实现
then
方法(可以说,then就是promise的核心),而且then必须返回一个promise,同一个promise的then可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致 - then方法接受两个参数,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用,同时,then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象
在使用Promise时,我们需要检测一些浏览器是否支持Promise

if(typeof(Promise)==="function") {
console.log("支持");
}
else {
console.log("不支持");
}

我们可以使用new Promise进行Promise的创建
function wait(time) {
return new Promise(function(resolve,reject) {
setTimeout(resolve,time);
});
}
这个时候我们就可以使用Promise处理异步任务啦
wait(1000).then(function(){
console.log(1);
})
上面这个例子表示1秒后输出1,同样的道理,我们可以使用Promise进行更加复杂的操作,关于更多的操作,就不继续说啦,关于异步的实现,其实还有其它的一些方法,但是因为上面说的这两种方法用的比较多,所以就只说上面这两种了
Promise-js中的同步和异步的更多相关文章
- 关于js中的同步和异步
最近看到前端面试问到js中的同步和异步,这个问题该怎么回答? 梳理一下,js对于异步的处理,很多人的第一反应是ajax,这只能说是对了一半. 1.个人觉得,js中,最基础的异步是setTimeout和 ...
- JS中的同步和异步
javascript语言是一门“单线程”的语言,不像java语言,类继承Thread再来个thread.start就可以开辟一个线程,所以,javascript就像一条流水线,仅仅是一条流水线而已,要 ...
- node.js中对同步,异步,阻塞与非阻塞的理解
我们都知道javascript是单线程的,node.js是一个基于Chrome V8 引擎的 javascript 运行时环境,注意 node.js 不是一门语言,别搞错了. javascript为什 ...
- js中的同步与异步
同步:提交后等待服务器的响应,接收服务器返回的数据后再执行下面的代码 异步:与上面相反,提交后继续执行下面的代码,而在后台继续监听,服务器响应后有程序做相应处理,异步的操作好处是不必等待服务器而 ...
- 【Mocha.js 101】同步、异步与 Promise
前情提要 在上一篇文章<[Mocha.js 101]Mocha 入门指南>中,我们提到了如何用 Mocha.js 进行前端自动化测试,并做了几个简单的例子来体验 Mocha.js 给我们带 ...
- JS中的同步异步编程
首先我们先看看同步与异步的定义,及浏览器的执行机制,方便我们更好地理解同步异步编程. 浏览器是多线程的,JS是单线程的(浏览器只分配一个线程来执行JS) 进程大线程小:一个进程中包含多个线程,例如 ...
- JS中的同步异步问题
<script> /* * JS 是单线程 * 同步 异步 * 常见的异步 * 1.定时器 * 2.事件绑定 * 3.ajax请求(一般的都是异步) * 4.回调函数也可以理解成 异步 * ...
- 让你高效的理解JavaScript中的同步、异步和事件循环
"同步请求","异步请求"相信这两词在程序猿的世界中频频出现,到底是词性的妖娆,还是撸代码的基础要求,下面直接分享本人学习的好东西,保证让你深入浅出,爽得不要不 ...
- js中对同步和异步的理解
你应该知道,javascript语言是一门“单线程”的语言,不像java语言,类继承Thread再来个thread.start就可以开辟一个线程,所以,javascript就像一条流水线,仅仅是一条流 ...
随机推荐
- Vm install centos7
- js地址多选实现,居住地,户口,职业,行业多选2
需求是根据点击一个按钮 实现动态添加数据,所以每个数据都有一个地址多选, 以下是效果实现及部分关键代码,相关js相关文件在 http://www.cnblogs.com/zhan1995/p/848 ...
- PHP中的Trait方法
<?php /* * 自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait. * Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制. * Trait ...
- MAVEN 自定义骨架
1)根据原由的骨架先创建出一个骨架模板,例如创建一个web框架可以先通过命令 mvn archetype:generate -DarchetypeCatalog=internal 创建出一个web的 ...
- day04_python_1124
01 上周内容回顾 int bool str int < --- > str: i1 = 100 str(i1) s1 = '10' int(s1)字符串必须是数字组成. in ...
- 个人前端学习路线图与github优秀前端开发者的路线图推荐
1.个人目前学习的路线图 2.github优秀前端开发者的路线图推荐 打开github首页,在搜索框输入developer-roadmap,搜索github前端路线图 选择kamranahmedse/ ...
- 过滤器 拦截器 登录login实例
当请求来的时候,首先经过拦截器/过滤器,在经过一系列拦截器/拦截器处理后,再由再根据URL找到Servlet.执行servlet中的代码. 过滤器:按照过滤的对象类型的不同,可分为按资源名过滤和按请求 ...
- hdu 1057 A + B Again
A + B Again Problem Description There must be many A + B problems in our HDOJ , now a new one is com ...
- (C/C++学习笔记) 一. 基础知识
一. 基础知识 ● 程序和C/C++ 程序: 根据Wirth (1976), Algorithms + Data Structures = Programs. Whence C: 1972, Denn ...
- 7.4 C++标准模板库(STL)的概念
参考:http://www.weixueyuan.net/view/6401.html 总结: 标准模板库为C++提供了完善的数据结构及算法. 标准模板库包括三部分:容器.算法和迭代器. 容器是对象 ...