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事件循环 事件循环 ...
随机推荐
- NET .NET深入体验和实战精要
在学习.NET之前要充分理解基础,在这里将基础的知识点一一列举. 万丈高楼平地起 1.命名空间 命名空间是一种特殊的分类机制,他将与一个特定功能集有关的所有类型都分到一起,是.避免类名冲突的一种方式 ...
- http长连接与短连接
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp23 http长连接与短连接 一.长连接与短连接: 长连接:client方与 ...
- AT&T汇编语言学习:利用c库、文件读写
AT&T汇编.调用C库函数.读/写文件 d0321:更新读文件代码(图片)以后会更新代码版. d0329:汇编文本读取.简单动画. ============================== ...
- 可以用 Python 编程语言做哪些神奇好玩的事情?
作者:造数科技链接:https://www.zhihu.com/question/21395276/answer/219747752 使用Python绘图 我们先来看看,能画出哪样的图 更强大的是,每 ...
- C# yield return用法
本文实例讲述了C#中yield return用法,并且对比了使用yield return与不使用yield return的情况,以便读者更好的进行理解.具体如下: yield关键字用于遍历循环中,yi ...
- 【深入Java虚拟机】之八:Java垃圾收集机制
转载请注明出处:http://blog.csdn.net/ns_code/article/details/18076173 对象引用 Java中的垃圾回收一般是在Java堆中进行,因为堆中几乎存放了J ...
- 201521123091 《Java程序设计》第11周学习总结
Java 第十一周总结 第十一周的作业. 目录 1.本章学习总结 2.Java Q&A 3.码云上代码提交记录及PTA实验总结 4.课后阅读 1.本章学习总结 1.1 以你喜欢的方式(思维导图 ...
- 201521123019 《Java程序设计》第7周学习总结
1. 本章学习总结 2. 书面作业 Q1.ArrayList代码分析 1.1解释ArrayList的contains源代码 源代码如下: public boolean contains(Object ...
- 201521123114 《Java程序设计》第3周学习总结
1. 本章学习总结 2. 书面作业 Q1.代码阅读 以上代码可否编译通过?哪里会出错?为什么?尝试改正? 如果创建3个Test1对象,有内存中有几个i,几个j?请分析原因? 不能编译通过,Test1g ...
- Java程序设计第三周学习总结
1. 本周学习总结 2. 书面作业 Q1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; ...