我们前端在日常开发中,经常会遇到我们当前请求的参数,需要从上一个请求的返回结果中获取,比如:
ajax('url1',params1, res1=>{
ajax('url2', res1.params2, res2=>{
console.log(res2);
// ...
})
})
如果多个请求有依赖关系,那么将会造成前端常见的回调地狱。这个时候Promise出现了,解决了层层嵌套的问题
ajax('url1', params1)
.then(res1=> {
return ajax('url2', res1.params);
})
.then(res2=> {
console.log(res2);
})
但是这种写法,还是会有.then().then()的拼接,虽然解决了层层嵌套,但是写起来依然很不爽。后来Async/Await出现了
async function load() {
const res1 = await ajax('url1', params1);
const res2 = await ajax('url2', res1.params2);
console.log('清爽无比')
}
load();
Async/Await是Generate+Co库的JS原生支持版本,那么它之前是长什么样子的呢?
在node环境下,我新建两个文件age.txt,name.txt
// name.txt
I am xiaoming
// age.txt
I am 18 years old
我要异步读取这两个文件,先读name.txt,再读age.txt
const fs = require('fs').promises; // node自带模块,读取文件返回一个Promise
function* read() {
const name = yield fs.readFile('./name.txt', 'utf8');
const age = yield fs.readFile('./age.txt', 'utf8');
return {
name,
age
}
}
const iterator = read();
const {value, done} = iterator.next(); // 第一个yield执行,返回一个Promise
// 为了让name有值,我们必须在next('name')中传参过去,否则name为undefined
// 所以我们需要再then中把resolve的值传递过去
value.then(data=> {
const {value, done} = iterator.next(data); // 给name赋值,执行下一个yield
return value;
}).then(data=> {
const {value, done} = iterator.next(data); // 给age赋值,return;
console.log(value, done); // { name: 'I am xiaoming', age: 'I am 18 years old' } true
})
为了优化.then().then()写法,我们把read()函数包装一下
const co = iterator=> {
return new Promise((resolve, reject)=> {
// 然后我们递归迭代这个函数,因为是generator的特性,我们第一步就要next它
next();
function next(data) {
const {value, done} = iterator.next(data);
if (!done) {
// 如果没有结束就一直往下迭代,value可能不是一个Promise,我们包装一下
Promise.resolve(value).then(next, reject);
} else {
// 最后的return值
resolve(value);
}
}
})
}
co(read()).then(data=> {
console.log(data) // { name: 'I am xiaoming', age: 'I am 18 years old' }
})