js-异步机制与同步机制
Javascript的优势之一是其如何处理异步代码。异步代码会被放入一个事件队列,等到所有其他代码执行后才进行,而不会阻塞线程
1 理解异步代码:
1.1 JavaScript最基础的异步函数是setTimeout和setInterval。setTimeout会在一定时间后执行给定的函数。它接受一个回调函数作为第一参数和一个毫秒时间作为第二参数。
- console.log(1);
- setTimeout(function() {
- console.log('a');
- },1000);
- setTimeout(function() {
- console.log('b');
- },1000);
- setTimeout(function() {
- console.log('c');
- },1000);
- console.log(2);
正如预期,控制台先输出1、2,大约500毫秒后,再看到“a”、“b”、“c”。我用“大约”是因为setTimeout事实上是不可预知的。实际上,甚至 HTML5规范都提到了这个问题:
“这个API不能保证计时会如期准确地运行。由于CPU负载、其他任务等所导致的延迟是可以预料到的。”
1.2 Event Loop队列
有趣的是,直到在同一程序段中所有其余的代码执行结束后,超时才会发生。所以如果设置了超时,同时执行了需长时间运行的函数,那么在该函数执行完成之前,超时甚至都不会启动。实际上,异步函数,如setTimeout和setInterval,被压入了称之为Event Loop的队列。
Event Loop是一个回调函数队列。当异步函数执行时,回调函数会被压入这个队列。JavaScript引擎直到异步函数执行完成后,才会开始处理事件循环。这意味着JavaScript代码不是多线程的,即使表现的行为相似。事件循环是一个先进先出(FIFO)队列,这说明回调是按照它们被加入队列的顺序执行的。
2 JQuery异步处理
异步Javascript与XML(AJAX)永久性的改变了Javascript语言的状况。突然间,浏览器不再需要重新加载即可更新web页面。 在不同的浏览器中实现Ajax的代码可能漫长并且乏味. 但是有些地方还是需要注意
- var data;
- $.ajax({
- url: "some/url/1",
- success: function( data ) {
- // 放在jquery指定的success函数里面可以保证异步请求完成
- console.log( data );
- }
- })
- // 这里并不能获取数据 ajax异步请求还未完成
- console.log( data );
容易犯的错误,是在调用$.ajax之后马上使用data,但是实际上是这样的
- xmlhttp.open( "GET", "some/ur/1", true );
- xmlhttp.onreadystatechange = function( data ) {
- if ( xmlhttp.readyState === 4 ) {
- console.log( data );
- }
- };
- xmlhttp.send( null );
- 底层的XmlHttpRequest对象发起请求,设置回调函数用来处理XHR的readystatechnage事件。
然后执行XHR的send方法。在XHR运行中,当其属性readyState改变时readystatechange事件就会被触发,
只有在XHR从远端服务器接收响应结束时回调函数才会触发执行。
3 回调函数--处理异步
异步编程很容易陷入我们常说的“回调地狱”。因为事实上几乎JS中的所有异步函数都用到了回调,连续执行几个异步函数的结果就是层层嵌套的回调函数以及随之而来的复杂代码。
eg: Nodejs中常见异步函数
- var fs = require( "fs" );
- fs.exists( "index.js", function() { // 回调函数处理异步
- fs.readFile( "index.js", "utf8", function( err, contents ) { // 回调函数处理异步
- contents = someFunction( contents ); // do something with contents
- fs.writeFile( "index.js", "utf8", function() { // 回调函数处理异步
- console.log( "全部按顺序执行完" );
- });
- });
- });
- console.log( "executing..." );
3.1 清除嵌套回调
3.1.1 命名函数避免双层嵌套,解决嵌套回调
清除嵌套回调的一个便捷的解决方案是简单的避免双层以上的嵌套。传递一个命名函数给作为回调参数,而不是传递匿名函数:
4 事件--处理异步
事件是另一种当异步回调完成处理后的通讯方式。一个对象可以成为发射器并派发事件,而另外的对象则监听这些事件。这种类型的事件处理方式称之为 观察者模式
5 Promise(ES6)--处理异步
- // 实例化 Promise对象
- let time = function(time) {
- return new Promise((resolve, reject) => {
- console.log('Promise实例化完成'); // Promise实例化后立即执行
- if (time >= 3000) {
- setTimeout(function(){
- resolve('大于3秒的时间后才显示出来');
- }, time)
- } else {
- reject('时间不能小于3秒')
- }
- });
- };
- // 实例化Promise对象后才能使用 then
- time(1000).then((value) => { // 1000 会走第二条判断Reject(Pending => Reject 失败会走第二个回调)
- console.log(value);
- }, (error) => {
- console.log(error);
- });
- console.log(1); // 'Promise实例化完成' 1 '时间不能小于3秒'
6 ES7的Async/Await--处理异步
- var sleep = function (time) {
- return new Promise(function(resolve, reject) { // 返回一个promise对象
- setTimeout(function() {
- resolve();
- }, time)
- })
- };
- var start = async function() {
- console.log('开始');
- await sleep(3000); // 等待异步过程完成再往下执行
- console.log('结束');
- }
- start();
- // 控制台先输出start,稍等3秒后,输出了end。
- 基本规则
- async 表示这是一个async(异步)函数,await只能用在这个函数里面。
- await 表示在这里等待promise返回结果了,再继续执行。
- await 后面跟着的应该是一个promise对象(当然,其他返回值也没关系,只是会立即执行,不过那样就没有意义了…)
- 获得返回值
- await等待的虽然是promise对象,但不必写.then(..),直接可以得到返回值。
- var sleep = function (time) {
- return new Promise(function (resolve, reject) {
- setTimeout(function () {
- // 返回 ‘ok’
- resolve('ok');
- }, time);
- })
- };
- var start = async function () {
- let result = await sleep(3000);
- console.log(result); // 收到 ‘ok’
- };
- // 获取异步结果
- let sleep = function (time) {
- return new Promise(function(resolve, reject){
- setTimeout(function() {
- resolve('异步返回结果');
- }, time)
- });
- };
- let start = async function() {
- let result = await sleep('3000');
- console.log(result);
- };
- start(); // 3秒后输出 '异步返回结果'
- // ** 捕获错误
- var asyncFn = function (time) {
- return new Promise((resolve, reject) => {
- setTimeout(function() {
- reject('异步出了问题');
- }, time)
- });
- };
- var start = async function() {
- console.log('开始');
- let result = await asyncFn(3000); // 返回了一个错误,不会往下执行了
- console.log(result);
- console.log('结束');
- };
- // 开始
- // (node:2200) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): 异步出了问题
- // (node:2200) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
- // 既然.then(..)不用写了,那么.catch(..)也不用写,可以直接用标准的try catch语法捕捉错误。
- var start = async function() {
- try{
- console.log('开始');
- let result = await asyncFn(3000); // 返回了一个错误,不会往下执行了
- console.log(result);
- console.log('结束');
- } catch(err) { //出了错误
- console.log(err)
- }
- };
- // 开始
- // 异步出了问题
- start();
参考资料
http://cnodejs.org/topic/5640b80d3a6aa72c5e0030b6
问题:
1 Promise是不是还是使用回调函数方式处理异步,但是避免了多重回调嵌套的问题?
An: Promise是处理异步的一种方式和回调函数处理异步方式是平行关系
js-异步机制与同步机制的更多相关文章
- 【转】C#异步编程及其同步机制
C#异步编程及其同步机制 本篇文章涵盖一下几部分内容: 1. 什么是异步编程,为什么会需要异步编程 2. .NET下的异步编程及其发展 3. .NET线程同步机制及线程间数据封送 4. 异步模式 5. ...
- 内核同步机制-RCU同步机制
转自:https://blog.csdn.net/nevil/article/details/7718375 转自http://www.360doc.com/content/09/0805/00/36 ...
- Zookeeper的选举机制和同步机制超详细讲解,面试经常问到!
前言 zookeeper相信大家都不陌生,很多分布式中间件都利用zk来提供分布式一致性协调的特性.dubbo官方推荐使用zk作为注册中心,zk也是hadoop和Hbase的重要组件.其他知名的开源中间 ...
- java 异步机制与同步机制的区别
所谓异步输入输出机制,是指在进行输入输出处理时,不必等到输入输出处理完毕才返回.所以异步的同义语是非阻塞(None Blocking). 网上有很多网友用很通俗的比喻 把同步和异步讲解的很透彻 转过 ...
- nginx源代码分析--进程间通信机制 & 同步机制
Nginx源代码分析-进程间通信机制 从nginx的进程模型能够知道.master进程和worker进程须要通信,nginx中通信的方式有套接字.共享内存.信号.对于master进程,从外部接受信号, ...
- Linux 多线程 - 线程异步与同步机制
Linux 多线程 - 线程异步与同步机制 I. 同步机制 线程间的同步机制主要包括三个: 互斥锁:以排他的方式,防止共享资源被并发访问:互斥锁为二元变量, 状态为0-开锁.1-上锁;开锁必须由上锁的 ...
- Java中的闪光点:ThreadLocal是线程Thead的局部变量,可替代同步机制的设计,值得学习和研究
线程局部变量ThreadLocal,是Java支持的一种线程安全机制,目的是解决多线程的并发问题. 具体来讲,就是多个线程访问该实例对象的变量时,该实例对象将其存储为键值对的形式,保证各个线程(键)分 ...
- linux kernel同步机制的思考
在学习内核同步机制的时候,书中介绍了同步方法:原子操作(atomic).自旋锁(spinlock).信号量(semaphore).互斥锁(mutex).完成变量(completion).大内核(BLK ...
- js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)
javascript是单线程,一切javascript版的"多线程"都是用单线程模拟出来的,通过事件循环(event loop)实现的异步. javascript事件循环 事件循环 ...
随机推荐
- mac系统webstorm快捷键
WebStorm 是jetbrains公司旗下一款JavaScript 开发工具.被广大中国JS开发者誉为"Web前端开发神器"."最强大的HTML5编辑器". ...
- 转:【Java并发编程】之二十三:并发新特性—信号量Semaphore(含代码)
载请注明出处:http://blog.csdn.net/ns_code/article/details/17524153 在操作系统中,信号量是个很重要的概念,它在控制进程间的协作方面有着非常重要的作 ...
- bean的生命周期以及延迟实例化
可以指定bean的初始化创建的时候调用的方法,以及销毁的时候调用的方法. 通过指定中的init-method和destroy-method方法指定bean的创建和销毁的时候执行类中的方法. 把lazy ...
- 201521123070 《JAVA程序设计》第4周学习总结
1. 本章学习总结 1.1 尝试使用思维导图总结有关继承的知识点. http://naotu.baidu.com/file/4de6f42e4f4f6cce0531dd9997b04e60?token ...
- 201521123098 《Java程序设计》第2周学习总结
1. 本周学习总结 1. 熟悉了一些码云中储存eclipse中代码的操作,利于随时储存代码,避免U盘丢失导致代码丢失的问题: 2. 了解了如何从码云中提取已储存的代码: 3. 学会了如何创建动态数组, ...
- 201521123106《java程序设计》第一周学习总结
1.本章学习总结 认识了java语言,了解了java的历史,学习了各种java相关文件的使用,能够进行基本的程序操作,学会了使用博客.码云. 2.书面作业 1.为什么java程序可以跨平台运行?执行j ...
- 201521123093 java 第九周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己 ...
- 201521123100 《Java程序设计》第13周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...
- Python学习笔记011_模块_标准库_第三方库的安装
容器 -> 数据的封装 函数 -> 语句的封装 类 -> 方法和属性的封装 模块 -> 模块就是程序 , 保存每个.py文件 # 创建了一个hello.py的文件,它的内容如下 ...
- 从输入 URL 到页面加载完成的过程中都发生了什么
从输入 URL 到页面加载完成的过程中都发生了什么 过程描述 浏览器查找域名对应的 IP 地址: 浏览器根据 IP 地址与服务器建立 socket 连接: 浏览器与服务器通信: 浏览器请求,服务器处理 ...