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事件循环 事件循环 ...
随机推荐
- NSMutable属性声明时为什么不能使用copy
在iOS开发里面我们经常会进行NSMutable(可变类型的类,常用的如NSMutableString,NSMutableArray,NSMutableDictionary,NSMutableData ...
- 我的hibernate学习记录(二)
通过上一篇文章我的hibernate学习记录(一)基本上的入门了hibernate,但是,里面还有还多东西是通过迷迷糊糊的记忆,或者说copy直接弄进去的,所以这篇文章就需要对上篇的一些文件.对象进行 ...
- 201521123087 《Java程序设计》第4周学习总结
1. 本周学习总结 2. 书面作业 注释的应用使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看.(截图) ...
- 201521123055 《Java程序设计》第3周学习总结
1. 本章学习总结 2. 书面作业 Q1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; ...
- 201521123059 《Java程序设计》第一周学习总结
第一周学习总结 1.本周学习总结 开学第周我们开始了JAVA学习,刚开始还有点懵,连熟悉相关的软件都要摸索很久,最后在看老师给的一些教程和课本的情况下安装了JDK和eclipse等软件,并进行了一次实 ...
- Struts2配置文件复用代码【web.xml、struts.xml、常量配置】
web.xml的分发器代码: <!-- 引入struts核心过滤器 --> <filter> <filter-name>struts2</filter-nam ...
- Hibernate table schema 的设置与应用
hibernate在实现实体映射时,DB无需强行指定.部署时会较对DB户名和密码,根据用户名以访问的表完成实体映射.如果一个帐号可以访问一个数据库的下多个表,以oracle为例用户user1下面有表t ...
- C#调用AForge实现摄像头录像
1: 首先下载库文件>> 也可以去官网寻找>> 下载本教程全代码>> 输出为MP4需要用到ffmpeg相关的文件,我打包的库已经带了,去官网找的库可以在这个目录找到 ...
- ubuntu中设置php7.0-fpm开机自启动
1.编写/etc/init/php7.0-fpm脚本如下 sudo vim /etc/init/php7.0-fpm #!/bin/sh### BEGIN INIT INFO# Provides: p ...
- 匹配替换第n个字符串
var name = "questions[0][question]",i=0; name.replace(/\[.+?\]/g, function(match, pos, ori ...