JS执行环境中负责执行代码的线程只有一个,排队等待执行。
特点总结如下:
大多数是同步执行,并不是同时执行,而是排队,按顺序执行。
缺点,如果耗时比较长的话,会造成阻塞,会出现卡死的现象。
不会去等待这个任务的结束才开始下一个任务。
难点,代码的执行顺序混乱。
消息队列,逐步执行
执行顺序图
备注:js是单线程的,但浏览器不是单线程的。有一个线程去监控倒计时,当倒计时结束之后,负责把这个任务放入消息队列。
所有异步编程方案的根基。
由调用者定义,交给执行者执行的函数。
const promise = new Promise(function(resolve,reject){
//这里用于 兑现 承诺
resolve(100);//承诺达成
//reject(new Error('promise rejected'));// 承诺失败
});
promise.then(function(val){
console.log('resolved',val);
},function(error){
console.log('rejected',error);
});
console.log('end');//end先输出,因为即使Promise里边没有时间延迟,但也需要放进消息队列执行,所以end先输出
function ajax(url){
return new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest();
xhr.open('GET',url);
xhr.responseType = 'json';
xhr.onload = function(){
if( this.status == 200 ){
resolve(this.response);
}else{
reject(new Error(this.statusText));
}
};
xhr.send();
})
}
ajax('/api/user.json').then(function(res){
console.log(res);
},function(error){
console.log(error);
})
then方法之后返回的也是一个promise对象。
每一个then方法实际上都是在为上一个then返回的promise对象添加状态明确之后的回调。
依次执行。
使用链式调用去代替之前的回调嵌套。
总结:
function ajax(url){
return new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest();
xhr.open('GET',url);
xhr.responseType = 'json';
xhr.onload = function(){
if( this.status == 200 ){
resolve(this.response);
}else{
reject(new Error(this.statusText));
}
};
xhr.send();
})
}
// 异常或者失败,用catch方法捕获错误
ajax('/api/user.json').then(function(res){
console.log(res);
}).catch(function(err){
console.log(err);
})
在全局对象中注册,捕获Promise错误。
浏览器环境:
window.addEventListener('unhandledrejection',event=>{
const {
reason,promise } = event;
console.log(reason,promise);
// reason Promise失败原因,一般是一个错误对象
// promise 出现异常的Promise对象
event.preventDefault();
},false);
node环境下:
最好的做法是,在代码中明确捕获每一个可能的异常
// Promise.resolve()
Promise.resolve('foo') //将字符串转换为Promise对象
.then(function(val){
console.log(val);//foo。
});
// 传入一个含有then方法的对象,转换为Promise,常用于Promise之前出现的库,转换为现在的Promise
Promise.resolve({
then:function(onFulfilled,onRejected){
onFulfilled('foo')
}
})
.then(function(val){
console.log(val);//foo。
});
//Promise.reject();
Promise.reject(new Error('rejected'))
.catch(function(err){
console.log(err);
})
Promise.all();
只有当里边任务全部完成, 才会成功结束
promise.race();
只会等待第一个结束的任务
回调队列中的任务称之为 宏任务
宏任务执行过程中可以临时加上一些额外需求
可以选择作为一个新的宏任务进到队列中排队
也可以作为当前任务的 微任务
直接在当然任务结束过后立即执行
Promise的回调会作为微任务执行。
微任务的作用,提高整体的响应能力。
绝大多数异步调用会作为宏任务进行调用
特殊的:
Promise & MutationObserver 作为微任务
nodejs里边的 process.nextTick 。
举例:
一个人去银行柜台办理存款业务。办理完存款业务之后。你又想办理信用卡。一般情况下,为了提供工作效率,业务员会顺带帮你一块办理。这就是宏任务里边的微任务。
程序也一样,为了提高执行效率,才有了微任务。
Generator配合 Promise 的异步方案
执行递归
try catch获取错误
github: https://github.com/tj/co
语言层面的异步编程标准。内部执行顺序,从上往下。不需要再配合CO这样的执行器
await 只能出现在 async 函数的内部