Javascript同步异步
JS三座大山
JavaScript是一门单线程的语言,因此,JavaScript在同一个时间只能做一件事,单线程意味着,如果在同个时间有多个任务的话,这些任务就需要进行排队,前一个任务执行完,才会执行下一个任务
JavaScript的单线程,与它的用途是有很大关系,JavaScript是浏览器的脚本语言
// 同步代码
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)
})
评论留言