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事件循环 事件循环 ...
随机推荐
- 使用Spring实现读写分离( MySQL实现主从复制)
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt403 1. 背景 我们一般应用对数据库而言都是"读多写少&quo ...
- Azure Powershell对ARM资源的基本操作
本分主要介绍Windows Azure Powershell对ARM资源的基本操作 1.登陆ARM模式,命令:Login-AzureRmAccount -EnvironmentName AzureCh ...
- VB与C#语言部分不用的地方Part1
1. 数据类型: ① 日期型(Date) 表示日期和时间用两个“#”符号把日期和时间的值括起来,如:#08/20/2001#.#2001-08-20#. ② 变体型(Variant) ...
- 【集美大学1411_助教博客】团队作业8——第二次项目冲刺(Beta阶段)
写在前面的话 此次团队作业8可以拆分成两部分:1.beta阶段冲刺计划安排,2.7天敏捷冲刺."我们很低调"没有使用leangoo,经过与张老师的商议,张老师同意他们不使用lean ...
- 3rd-Bing Dict使用分析
英语学习APP的案例分析 0x00 写在前面 我们生活中很多时候要和软件打交道,大家上课开小差时候玩的手机游戏,买火车票的网站,互相联系用的微信.QQ,等等都是软件,都很值得分析.你为何成为它们的用户 ...
- 201521123065《java程序设计》第8周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 1.Map通过get(key)来获取值: 2.HashMap和Hash ...
- 201521123049 《JAVA程序设计》 第4周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. ###1.类型转换(cast):是将两种不同类型的变量进行转换,但不能随意强制转换,随意强制 ...
- 201521123060 《Java程序设计》第3周学习总结
1. 本周学习总结 2. 书面作业 1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; p ...
- 201521123006 《Java程序设计》 第2周学习总结
1. 本周学习总结 本周进一步学习了java,了解了java编程中一些特定的用法,比如:在编译程序时可以使用import来减少输入包名称.本周还学会了使用枚举类(enum Choice{fab,sor ...
- [android游戏开发初学]SurfaceView初探之缓冲区测试
先上测试代码 private static class PathView extends SurfaceView implements SurfaceHolder.Callback{ private ...