Javascript是单线程的,同一时间只能做一件事。 JS 有事件循环,主线程和任务队列,同步任务放入主线程,只有上一个任务执行完,才执行下一个任务,异步任务则放入任务队列,只有主队列的任务全部执行完才请求任务队列。 JS 是单线程,而同步很容易发生堵塞情况,因此异步就成了多数情况的选择。异步编程一直是编程人员致力解决的问题,为此诞生了许许多多的解决方案和思路。
Promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象,Promise对象有两个特点:不受外部影响,状态一旦确定就不在变化。
Promise 构造函数接收一个函数作为参数,改函数的两个参数为 resolve 和 reject 。由javascript引擎提供。
const promise=new Promise((resolve,reject)=>{
if(未来事件){ //某个未来才结束的事件,通常为异步操作
resolve(res) //将状态从pending 转为 resolve(成功),并放出参数
}else{
reject(err) //将状态从pending 转为 reject(失败),并放出参数
}
})
// Preomise的实例生成后,由 .then() 指定分别指定 resolve 和 reject 状态的回调函数
promise
.then((response)=>{ // resolve响应函数
console.log(response)
})
.catch((error)=>{ // reject 响应函数
console.log(error)
})
.finally(()=>{ // 无法读取状态,与状态无关,总会执行
console.log('')
})
Promise 可以应用于一些异步执行的问题,如 Axios请求 return数据异步问题
Generator
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。
Generator 函数是一个普通函数,但是有两个特征,function关键字和函数名之间有一个星号,函数内部用 yield 表达式来定义不同的内部状态
function* generator(num){
yield '推出的参数'; // yield 类似于暂停关键点,next()执行到就停
console.log(num)
yield 1 + 2;
yiele num + 1;
// return num return 会把 done 状态改为 true,之后的 yield 就不执行了
yield* generator // 如果 yield 身后跟着遍历器对象,就需要在添加星号
}
let gen = generator() // 函数并未执行
gen.next() // {value:'推出的参数,done:false}
Generator 函数可以应用于解决一些状态机的问题,设置无限循环,每次执行函数都进行状态更换
例子:
function* clock() {
while (true) {
console.log('开!');
yield true; // 执行第1次将状态返回true,并暂停执行
console.log('关!');
yield false; // 执行第2次将状态返回false,并重新循环
}
};
async
ES2017标准引入了 async 函数,使得异步操作变得更加方便。async 函数是什么?一句话,它就是 Generator 函数的语法糖
const async = async function () { // async 将 * 替换为 async
const f1 = await readFile('/etc/fstab'); // async 将 yield 替换为 await
const f2 = await readFile('/etc/shells');
};
// 和普通函数一样的执行方式,但是返回 Promise 对象,可以使用then() 方法处理返回对象
async().then((value)=>{
console.log(value)
})
如果 await语句后面的 Promise 对象变为 reject状态,那么整个 async函数都会中断执行。如果想前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个await放在try…catch结构里面,或者使用 .catch() 。这样不管这个异步操作是否成功,第二个await都会执行
async function fun(){
try {
await Promise.reject('出错了');
} catch(e) {
}
// .catch((err)=>{ })
return await Promise.resolve('hello world');
}
Axios关于异步导致的返回数据undefined
在Axios 中,使用的是异步请求,这就会导致一个问题,如果需要等这个请求的返回数据的函数会在 Axios未返回数据之前就执行了,就没有拿到数据,返回undefined。这就需要使用Promise或者其他异步处理
export function Power(){
return new Promise((resolve,reject)=>{
let hash=location.href.split('/#/')[1]
let power=false
axios.post('httpss://xxxxxx',{})
.then(function(response){
let menu=response.data.Menulist
for(let i in menu){
if(menu[i].url==hash){
power=true
break
}
}
resolve(power)
})
.catch(function (error){
reject(power)
});
})
}