##JS三座大山
JavaScript是一门单线程的语言,因此,JavaScript在同一个时间只能做一件事,单线程意味着,如果在同个时间有多个任务的话,这些任务就需要进行排队,前一个任务执行完,才会执行下一个任务
###JavaScript的单线程,与它的用途是有很大关系,JavaScript是浏览器的脚本语言
###异步的产生原因
1、定时器都是异步操作
2、事件绑定都是异步操作
3、AJAX中一般我们都采取异步操作
4、回调函数可以理解为异步
// 同步代码
function fun1() {
console.log(1);
}
function fun2() {
console.log(2);
}
fun1();
fun2();
// 输出
1
2
##表白的案例
##同步和异步
因为JavaScript的单线程,因此同个时间只能处理同个任务,所有任务都需要排队,前一个任务执行完,才能继续执行下一个任务,但是,如果前一个任务的执行时间很长,比如文件的读取操作或ajax操作,后一个任务就不得不等着,拿ajax来说,当用户向后台获取大量的数据时,不得不等到所有数据都获取完毕才能进行下一步操作,用户只能在那里干等着,严重影响用户体验
###同步任务
同步任务是指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务,当我们打开网站时,网站的渲染过程,比如元素的渲染,其实就是一个同步任务
###异步任务
异步任务是指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,当我们打开网站时,像图片的加载,音乐的加载,其实就是一个异步任务
##异步
异步(Asynchronous, async)
同步(Synchronous, sync)
function fun1() {
console.log(1);
}
function fun2() {
console.log(2);
}
function fun3() {
console.log(3);
}
fun1();
setTimeout(function(){
fun2();
},0);
fun3();
// 输出
###异步机制
- 所有同步任务都在主线程上执行,行成一个执行栈
- 主线程之外,还存在一个任务队列,只要异步任务有了结果,就会在任务队列中放置一个事件
- 一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面还有哪些事件,那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行
- 主线程不断的重复上面的第三步
###JS 异步编程进化史
async/await可以说是异步终极解决方案了
##异步编程
###回调函数(callback)
AJAX。。。
setTimeout
setTimeout(() => {
task();
},3000)
console.log('执行console');
// 执行console
// task()
⁃
setTimeout(() => {
task()
},3000)
sleep(10000000)
⁃
console.log('先执行这里');
setTimeout(() => {
console.log('执行啦')
},0);
// 先执行这里
// 执行啦
###回调不一定是异步
function A(callback){
console.log("A");
callback(); //调用该函数
}
function B(){
console.log("B");
}
A(B);
####回调函数的优点是简单、容易理解和部署
####缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数
##Promise
JavaScript处理异步都是以callback的方式,在前端开发领域callback机制几乎深入人心,近几年随着JavaScript开发模式的逐渐成熟,CommonJS规范顺势而生,其中就包括提出了Promise规范,Promise完全改变了js异步编程的写法,让异步编程变得十分的易于理解,同时Promise也已经纳入了ES6,而且高版本的chrome、firefox浏览器都已经原生实现了Promise
优点 | 缺点 |
---|---|
解决回调 | 无法检查进行状态 |
链式调用 | 建立且执行无法取消 |
减少嵌套 | 内部错误无法捕捉 |
- 一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)
- 一个promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换,同时“完成”态和“拒绝”态不能相互转换
- promise必须实现then方法(可以说,then就是promise的核心),而且then必须返回一个promise,同一个promise的then可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致
- then方法接受两个参数,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用,同时,then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象
new Promise(function (resolve, reject) {
// do …
});
if(typeof(Promise)==="function") {
console.log("支持");
}
else {
console.log("不支持");
}
setTimeout(function () {
console.log("1");
setTimeout(function () {
console.log("2");
setTimeout(function () {
console.log("3");
}, 3000);
}, 4000);
}, 1000);
new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("First");
resolve();
}, 1000);
}).then(function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("Second");
resolve();
}, 4000);
});
}).then(function () {
setTimeout(function () {
console.log("Third");
}, 3000);
});
###格式
new Promise(function (resolve, reject) {
console.log("Run");
});
new Promise(function (resolve, reject) {
console.log(1);
resolve(2);
}).then(function (value) {
console.log(value);
return 3;
}).then(function (value) {
console.log(value);
throw "error";
}).catch(function (err) {
console.log(err);
});
###再来一种写法
let promise = new Promise(function(resolve, reject){
console.log("1");
resolve()
});
promise.then(() => console.log("2"));
console.log("3)
console.log("program start....")
function funs(c){
return new Promise(function(resolve,reject){
resolve(c+",world");
});
}
funs('hello')
.then(function(retulet){
console.log(retulet)
})
.then(function(){})
.catch(function(){})
console.log("program end....")
###promise copy
var hello = new Promise(function(resolve,reject){
setTimeout(function(){
var text = "你好,我是saoge";
console.log(text);
resolve(text);
},1000)
})
var say = new Promise(function(resolve,reject){
setTimeout(function(text){
console.log(text);
},1000)
})
##混合异步
setTimeout(function() {
console.log('我是定时器!');
})
new Promise(function(resolve) {
console.log('我是promise!');
resolve();
}).then(function() {
console.log('我是then!');
})
console.log('我是主线程!');
###题目一:
setTimeout(() => {
console.log(1);
}, 0);
new Promise((resolve) => {
console.log(2);
resolve();
}).then(() => {
console.log(3);
});
console.log(4);
// 输出最后的结果
(1)setTimeout丢给浏览器的异步线程处理,因为时间是0,马上放入消息队列
(2)new Promise里面的console.log(2)加入执行栈,并执行,然后退出
(3)直接resolve,then后面的内容加入微任务队列
(4)console.log(4)加入执行栈,执行完成后退出
(5)检查微任务队列,发现有任务,执行console.log(3)
(6)发现消息队列有任务,执行下一次宏任务console.log(1)
###题目二:
setTimeout(() => {
console.log(1);
}, 0);
new Promise((resolve) => {
console.log(2);
setTimeout(() => {
console.log(5);
}, 0);
resolve();
}).then(() => {
console.log(3);
});
// 输出最后的结果
console.log(4);(1)setTimeout丢给浏览器的异步线程处理,因为时间是0,马上放入消息队列
(2)new Promise里面的console.log(2)加入执行栈,并执行
(3)setTimeout给浏览器的异步线程处理,因为时间是0,马上放入消息队列,然后退出
(4)直接resolve,then后面的内容加入微任务队列
(5)console.log(4)加入执行栈,执行完成后退出
(6)检查微任务队列,发现有任务,执行console.log(3)
(7)发现消息队列有任务,执行下一次宏任务console.log(1)
(8)发现消息队列有任务,执行下一次宏任务console.log(5)
setTimeout(() => {
console.log(1);
}, 0);
new Promise((resolve,reject) =>{
console.log(2)
resolve(3)
}).then((val) =>{
console.log(val);
})
console.log(4);
// 输出最后的结果
###题目三:1)先执行script同步代码:
先执行new Promise中的console.log(2),then后面的不执行属于微任务然后执行console.log(4)
(2)执行完script宏任务后,执行微任务,console.log(3),没有其他微任务了
(3)执行另一个宏任务,定时器,console.log(1)
####题目四:
let a = () => {
setTimeout(() => {
console.log(‘任务队列函数1’)
}, 0)
for (let i = 0; i < 5000; i++) {
console.log(‘a的for循环’)
}
console.log(‘a事件执行完’)
}
let b = () => {
setTimeout(() => {
console.log(‘任务队列函数2’)
}, 0)
for (let i = 0; i < 5000; i++) {
console.log(‘b的for循环’)
}
console.log(‘b事件执行完’)
}
let c = () => {
setTimeout(() => {
console.log(‘任务队列函数3’)
}, 0)
for (let i = 0; i < 5000; i++) {
console.log(‘c的for循环’)
}
console.log(‘c事件执行完’)
}
a();
b();
c();
// 输出最后的结果
结果是当a、b、c函数都执行完成之后,三个setTimeout才会依次执行
Was this helpful?
0 / 0