异步问题得到解决 : 可以获取到异步操作内的数据
异步的原理:
都知道js是单线程的,所谓的单线程就是一次只能完成一个任务,其任务的调度方式就是排队,毫无疑问,这样的效率是不高的,后面的任务必须等到前面的任务执行完毕后才能执行,如果有一个比较耗时的操作,比如http请求,文件io。
其他语言遇到这种比较耗时的任务往往是开一个线程来处理,但js本身就是单线程的,js对这种任务的处理就是这个一个任务挂载起来,等耗时任务完成后再把回调函数添加到执行队列尾部。
1. 回调函数
const f1 = (call) => {
setTimeout(() => {
call('123') //两秒后输出123
}, 2000)
}
f1((val) => console.log(val))
const aa = (call) => {
let x = 1
setTimeout(() => {
var y = 2
console.log(`函数内x=${x}`)
return call(y)
}, 1000)
}
aa((arg) => {
console.log(`回调函数内获得了y=${arg}`)
})
//结果:
//函数内x=1
//回调函数内获得了y=2
数据复杂的时候,会出现嵌套很多层的情况。有局限性。
假定有三个函数f1(),f2(),f3()。
f1执行很耗时,而 f2需要在f1执行完之后执行。
//最原始的写法-同步写法
f1(); //耗时很长,严重堵塞
f2();
f3(); //导致f3执行受到影响
为了不影响 f3的执行,我们可以把f2写成f1的回调函数。
//改进版-异步写法
function f1(callback){
setTimeout(function () {
// f1的任务代码
callback();
}, 1000);
}
f1(f2); //
f3();
- 回调函数的本质是闭包
function callback(val) { //声明回调函数
console.log(val)
}
function f1(callback) { //回调函数作为参数传入f1函数
let n = 99;
callback(n) //执行回调函数
}
f1(callback) //获取到f1中的值n
回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合,流程会很混乱,而且每个任务只能指定一个回调函数。
2. Generator
const fn = () => {
setTimeout(() => {
g.next('???') // {value:undefined,done:true} // 第二个yield
// next的参数传给第一个yield
})
}
function* gn() {
let tip = yield fn()
console.log(tip) // 输出 ???
}
let g = gn()
g.next() // {value:undefined,done:false}
// 第一个yield // 表示开始执行 generator
- yield后面是一个包含异步操作的对象
- generator内可以将异步写成同步
- 第一个.next()执行第一个yield后面的内容。
- 第二个.next()传的内容赋值给第一个yield.
.next() 括号里的内容 传值给上一个yield
【小插曲】
let ps = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise-ok') //两秒后输出 promise-ok
}, 2000)
})
function* gn() {
let res = yield ps;
console.log(res) // 1
}
let g = gn()
g.next().value.then(res => console.log(res))
g.next(1)
//结果
//1
// promise-ok
promise-ok的经历:
- 第一个next()执行的是第一个yield → yield ps。
- console.log(g.next()),结果是{value:undefined,done:false}。这里面的value就是ps,一个promise对象。
- 通过.then链式调用获得resolve的内容。
- 打印promise-ok。
3. Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第一个promise的console')
resolve('第一个resolve')
}, 2000)
})
p1.then(res => {
console.log(res)
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第二个promis的console')
resolve('第二个resolve')
}, 2000)
})
}).then(res => {
console.log(res)
})
//结果
// 第一个promise的console // 两秒后
// 第一个resolve // 两秒后
// 第二个promis的console // 四秒后
// 第二个resolve // 四秒后
上述回调函数的改进:
const aa = () => {
let x = 1;
return new Promise((res, rej) => {
setTimeout(() => {
let y = 2
res(y)
}, 1000)
})
}
aa().then(res => console.log(`y=${res}`))
ajax运用promise
![](https://img.haomeiwen.com/i14173157/3742f6b8d324ac6d.png)
![](https://img.haomeiwen.com/i14173157/aeafe98f60f9578e.png)
4. async / await
const ps = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('???')
}, 2000)
})
async function gn() {
let res = await ps
console.log(res) // ???
}
gn()
sync函数就是Generator函数的语法糖。
async不过是把Generator函数的*号换成async,yield换成await。
async函数的优点
(1)内置执行器
Generator 函数的执行必须靠执行器,所以才有了 co 函数库,而 async 函数自带执行器。也就是说,async 函数的执行,与普通函数一模一样,只要一行。
(2) 语义化更好
async 和 await,比起星号和 yield,语义更清楚了。async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
(3)更广的适用性
yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。
-
在vue中,axios结合async/await
3.png
部分内容来自网络,之前记录的时候忘了记下出处,欢迎有发现的好心人提出指正~
网友评论