异步编程
随着计算机的不断发展,用户对计算机应用的要求越来越高,需要提供更多、更智能、响应速度更快的功能。这就离不开异步编程的话题。同时,随着互联网时代的崛起,网络应用要求能够支持更多的并发量,这显然也要用到大量的异步编程。
进程指的是系统任务,线程指的是应用任务。
每个正在运行的程序(即进程),至少包括一个线程,这个先储层叫主线程
一:同步和异步任务
概念:同步就是就是在发出一个"调用"时,在没有得到结果之前,该“调用”就不返回。但是一旦调用返回,就得到返回值了;异步就是当一个异步过程调用发出后,调用者不会立刻得到结果。而是在"调用"发出后,"被调用者"通过状态、通知来通知调用者,或通过回调函数处理这个调用
举例:就是你想要当你想边做作业边听歌时,同步做的就是先把作业做完再听歌是一个任务结束后才能执行另一个任务;异步就是在你做作业的时候把歌打开,边听歌边做作业
js只有一个线程,先执行同步操作再执行异步操作;把同步操作执行的时候,把异步操作放入时间队列当中(先进先出);当同步操作中后面的时间到了,后面的就先输出。
console.log("开始");
console.log("运行");
setTimeout(() => {
console.log("nihao1");
}, 1000)
setTimeout(() => {
console.log("nihao2");
}, 500)
console.log("借宿");
/**开始
运行
借宿
nihao2
nihao1**/
异步任务
概念:异步任务分为宏任务(macroTask)
,微任务(microTask)
- 宏任务:宿主对象产生的(包括整体代码script,setTimeout,setInterval, setImmediate)
- 微任务:js引擎产生(Promise等)
- 先执行微任务再执行宏任务
setTimeout(()=>{
console.log('1');
},0);
new Promise((resolve)=>{
console.log('2');
resolve();
}).then(()=>{
console.log('3');
})
console.log('4');
//2,4,3,1
//同步2,4;异步1,3s
//因为3为微任务所以3先出来
二:单线程和多线程
概念:单线程就是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器);多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
举例:就是去游乐园买票的时候,只有一个窗口,一个窗口排了9个人,只能一个接一个的买票才能全部卖完,只有一个窗口就是单线程;多线程就是有多个窗口提供使用排队的人可以排列到其他窗口同时进行
三:阻塞和非阻塞
概念:阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程.
举例:就是在只有一个窗口排队买票的时候,当要付钱的时候,当前的买票人手机二维码网太卡,转不出来,当服务员等待这个人把二维码调出来付款成功后才能接待下一个人,这就是阻塞;当服务员没有等这个人的二维码出来,直接接待后面客人,当二维码顾客把二维码调试出来后才让他付款,这就是非阻塞。
四:回调地狱
概念:多次回调嵌套如:
setTimeout(() => {
console.log("吃饭");
setTimeout(() => {
console.log("睡觉");
setTimeout(() => {
console.log("打豆豆");
}, 1000)
}, 1000)
}, 1000)
// 当参数a大于10且参数fn2是一个方法时 执行fn2
function fn1(a, fn2) {
if (a > 10 && typeof fn2 == 'function') {
fn2()
}
}
fn1(11, function() {
console.log('this is a callback')
})
五:解决回调地域问题:Promise
Promise概念:是异步编程的一种解决方案:从语法上讲,promise是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。promise有三种状态: pending(等待态),fulfiled(成功态),rejected(失败态);状态一旦改变,就不会再变。创造promise实例后,它会立即执行。
es6中promise用法大全
Promise是一个构造函数,自己身上有all、reject、resolve这几个眼熟的方法,原型上有then、catch等同样很眼熟的方法。
语法格式:
let promise = new Promise((resolve,reject)=>{});
promise.then(()=>{
//成功后执行的代码
});
- resolve :异步操作执行成功后的回调函数
- reject:异步操作执行失败后的回调函数
.then
:用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。
//es6解决异步代码
<script>
console.log("开始");
console.log("进行");
let promise = new Promise((resolve, reject) => {
console.log("异步执行的代码");
// resolve();
reject();
});
promise.then(() => {
console.log("执行成功的异步代码");
}, () => {
console.log("执行失败的异步代码");
});
console.log("结束");
</script>
//Promise es6实现异步操作
function timeOut(time){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve();
},time)
})
}
console.log("开始");
let promise = timeOut(1000);
promise.then(()=>{
console.log("吃饭");
return timeOut(1000);
}).then(()=>{
console.log("睡觉");
return timeOut(1000);
}).then(()=>{
console.log("打豆豆");
});
es7中的方法
概念:ECMAScript 7 提出的async
函数,让异步代码变得更为简洁。
实际上 async 只是生成器的一种语法糖而已,简化了外部执行器的代码,同时利用 await 替代 yield,async 替代生成器的*
号。
- async:加在function前面
- await:加载函数里面
//Promise es7实现异步操作
function timeOut(time){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve();
},time)
})
}
console.log("开始");
async function delay(){
await timeOut(1000);
console.log("吃饭");
await timeOut(1000);
console.log("睡觉");
await timeOut(1000);
console.log("打豆豆");
}
delay();
console.log("结束");
迭代器和生成器的结合
function timeOut(time){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve();
},time)
})
}
console.log("开始");
function* delay(){
yield timeOut(1000);
yield timeOut(1000);
yield timeOut(1000);
}
let cs = delay();
cs.next().value.then(()=>{
console.log("吃饭");
return cs.next().value;
}).then(()=>{
console.log("睡觉");
return cs.next().value;
}).then(()=>{
console.log("打豆豆");
})
console.log("结束");
六:迭代器和生成器
迭代器(Iterator):.next()
.then
:在正确的时候执行代码- 不能调用两次next不管是输出还是啥,不然结果会有问题
概念:
- 在 JavaScript 中,迭代器是一个对象,它定义一个序列,并在终止时可能返回一个返回值
- 迭代器是通过使用
next()
方法实现Iterator protocol
的任何一个对象,该方法返回具有两个属性的对象:value
,这是序列中的 next 值;和done
,如果已经迭代到序列中的最后一个值,则它为 true,否则false - Javascript中最常见的迭代器是Array迭代器,它只是按顺序返回关联数组中的每个值。
- 它允许创建一个简单的范围迭代器,它定义了从开始(包括)到结束(独占)间隔步长的整数序列。 它的最终返回值是它创建的序列的大小,由变量
iterationCount
跟踪。
数组的迭代器
<!--数组的迭代器-->
<script>
let arr = [10, 20, 30, 40, 50];
let iterator = arr[Symbol.iterator]();
//while (true) {
// let item = iterator.next();
// if(item.done){
// break;
// }
// console.log(item);
// }
console.log(iterator.next()); //{value: 10, done: false}
console.log(iterator.next()); //{value: 20, done: false}
console.log(iterator.next()); //{value: 30, done: false}
console.log(iterator.next()); //{value: 40, done: false}
console.log(iterator.next()); //{value: 50, done: false}
console.log(iterator.next()); //{value: undefined, done: true}
//done:迭代到序列中的最后一个值,则它为 true
</script>
集合的迭代器
//集合的迭代器(Map(),Set())
let map = new Map();
map.set("name", "张三");
map.set("age", 18);
map.set("gender", "男");
let iterator = map.entries();
while (true) {
let item = iterator.next();
if (item.done) {
break;
}
console.log(item.value[0],item.value[1]);
}
/* name 张三
age 18
gender 男 */
自定义集合的迭代器
//自定义对象迭代器
let obj = {
"name": "zhangsna",
"gender": "男",
"age": 18,
[Symbol.iterator]: function () {
let index = 0;
let keys = Object.keys(this);
return {
next: function () {
return {
value: keys[index++],
done: index > keys.length
}
}
}
}
}
let iterator = obj[Symbol.iterator]();
while (true) {
let item = iterator.next();
if (item.done) {
break;
}
console.log(item);
console.log(obj[item.value]);
}
/**
* {value: 'name', done: false}
* zhangsna
* {value: 'gender', done: false}
* 男
* {value: 'age', done: false}
* 18
* **/
生成器(generator):function*
生成器返回的是一个迭代器
yield
:挂起代码,在想用的地方调用就行
概念:
- 它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态
- 最初调用时,生成器函数不执行任何代作用码,而是返回一种称为
Generator
的迭代器。 - 通过调用生成器的下一个方法消耗值时,Generator函数将执行,直到遇到
yield
关键字。 - 可以根据需要多次调用该函数,并且每次都返回一个新的Generator,但每个Generator只能迭代一次。
<p>我说 <span id="content"></span></p>
<input type="button" value="点击" id="btn">
let content = document.getElementById("content");
let btn = document.getElementById("btn");
function* say() {
yield "嗨";
yield "你在干啥呢";
yield "我在吃饭呢,等会找你玩哈";
yield "看到消息请回复,拜拜";
}
//生成器返回的是一个迭代器
let iterator = say();
btn.onclick = function () {
// console.log(iterator.next());
let aa = iterator.next();
if (!aa.done) {
// console.log(aa.done);
content.innerHTML = aa.value;
}
else{
content.innerHTML = "......";
}
}