由于JavaScript的执行环境是单线程的,导致js代码的两种执行方式:
- 以js代码的先后顺序执行的顺序型
- 以事件驱动触发执行的事件型
以js代码的先后顺序执行的顺序型
也就是所谓的同步执行,相对于位置靠前的代码执行完成,才去执行后续的代码
console.log('1');
console.log('2');
以事件驱动触发执行的事件型
function c(){
console.log('3');
}
console.log('1');
onclick = c();
console.log('2');
异步执行:只要不阻断js主线程执行而执行的代码都是异步执行,以上点击事件触发函数c()的执行并不影响后续代码执行;所以所有的事件触发函数都是异步执行,也就是第一种异步执行方式:事件监听
从
onclick = c();
我们探讨异步执行的第二种方式:发布-订阅模式:
首先onclick
是js原生事件,那么换成我们自定义的事件,就构成了所谓的发布订阅模式,自定义事件参照自定义事件
- 订阅
Event.on('click',fn)
- 发布
Event.emit('click')
以上我们自定义的事件
click
的触发fn
的执行不影响主线程的执行顺序,所以fn
函数代码为异步执行;从事件的发布订阅模式,我们探讨第三种异步执行方式:回调函数
const event = {};
function on(type,callback){
event.type = callback;
}
function emit(type){
event.type();
}
以上就是最简单的一个事件的发布订阅,可以看出归根结底就是一个
callback
的执行,以下是一个简单的异步回调:
function A(callback){
console.log("I am A");
callback();
console.log("I am C")
}
function B(){
setTimeout(function(){
console.log("I am B");
},1000)
}
A(B);
从回调函数我们探讨第四种异步执行方式
promise
:
class Promisser{
constructor(callback) {
this.res = this.res.bind(this);
this.rej = this.rej.bind(this);
this.state = {};
callback(this.res,this.rej)
}
res(val){
this.state.success = val
}
rej(err){
this.state.error = err
}
then(resCallback,rejCallback){
Object.defineProperty(this.state,'success',{
get: function () {
return this.state
},
set: function (newValue) {
resCallback(newValue);
}
})
Object.defineProperty(this.state,'error',{
get: function () {
return this.state
},
set: function (newValue) {
rejCallback(newValue);
}
})
}
}
const test = new Promisser(function(res,rej){
setTimeout(()=>{
res('success')
},1000)
setTimeout(()=>{
rej('error')
},2000)
})
test.then((res)=>{
console.log('111111',res) //111111 success
},(rej)=>{
console.log('222222',rej) //222222 error
})
以上是一个简单的
promiss
原生模拟实现,可以看出,归根结底也是监听对应状态的变化触发对应callback
的执行,只是执行的位置移到了函数外部;
综上所述
js中异步执行的方式:事件监听,事件的发布-订阅,
promise
对的异步执行原理都是回调函数,也是js异步执行的主要方式;
其他异步执行方式
另外的异步执行方式es6的新式api Generator函数与之对应的语法糖
async
函数,这里不做讨论。
网友评论