async函数

首先看一下下列代码

var gen = function* (){
 var a = yield readFile();
 console.log(a);
 var b= yield readFile();
 console.log(b);
}

接下来用async形式来表示generator函数

var gen = async function(){
 var a = await readFIle();
 console.log(b);
 var b = await readFile();
 console.log(b);
}

从以上可以看出async函数就是在generator函数上改进的,就是把*改为async,然后把yield改为await,但是他在generator函数上有一些改进

哪些改进呢?


  • 内置执行器
    在我的另一篇博客中说出generator函数执行,需要为他写自动执行器,例如基于thunk函数的自动执行器,还有基于promise的自动执行器,还有就是co模块,但是async函数只要调用它就自己执行
  • 更好的语义
  • 更广泛的使用
    co模块的yield语句后面必须是thunk函数或者是promise对象,但是await函数后面可以是原始类型的值
  • 返回的是promise对象
    可以使用then等

使用方法


async function getStockByName(name){
 const symbol = await getStockSymbol(name);
 const stockPrice = await getStockPrice(symbol);
 return stockPrice;
}
getStockByName('sportShoe').then(function(result){
 console.log(result);
})

我们可以看出只要我们调用一次getStockByName(),就自动执行,所以最后的result就是stockPrice

语法


返回Promise对象

调用async函数会返回一个promise对象,所以才可以调用then方法,then方法中的函数的参数就是async函数返回的值

const aw = async function(age){
 var name = await search(age);
 return name;
}
aw(20).then(name => console.log(name));

promise对象的状态变化

只有内部的所有异步过程结束后,才会调用then方法,或者抛出错误,或者遇到return语句

错误处理

我建议大家把所有的await语句都放在try catch语句中

async function main() {
try {
  const val1 = await firstStep();
 const val2 = await secondStep(val1);
 const val3 = await thirdStep(val1, val2);
 console.log('Final: ', val3);
}
catch (err) {
 console.error(err);
}
}

注意的内容

let foo = await getFoo();
let bar = await getBar();

以上函数是独立的过程,被写成继发关系,就是顺序进行,这样会导致很费时,怎样会写成同时进行
有一下俩种写法

// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

promise.all()方法就是将多个promise实例包装成一个
await命令必须写在async函数中写在别的函数中会出错

async函数的实现的原理

其实就是把generator函数写到一个具有自动执行代码的函数,然后在返回这个函数,和基于thunk函数的自动执行器基本一致,就不仔细分析async函数的源码了

顺序执行完一系列操作

promise的写法

function loginOrder(urls){
Const textPromises = urls.map(url => {
Return fetch(url).then(response => response.text());
})
TextPromise.reduce((chain, textPromise) => {
Return chain.then(() => textPromise)
.then(text => console.log(text));
}, Promise.resolve());
}

接下来看一下用async函数来表示上述操作

async function logInOrder(urls) {
for (const url of urls) {
const response = await fetch(url);
console.log(await response.text());
}
}

可以看出来用async表示非常简洁,但是这样会有一个问题所有提取网页都是继发,这样会很浪费时间,继发·就是提取网页是按照顺序进行的,所以我们现在要把它改成同时提取网页,代码如下

async function logInOrder(urls) {
// 并发读取远程URL
const textPromises = urls.map(async url => {
const response = await fetch(url);
return response.text();
});
// 按次序输出
for (const textPromise of textPromises) {
console.log(await textPromise);
}
}

因为在上述map函数中,匿名函数是async函数,所以await如果是在async函数中,那么这些await后面的操作都是同步进行的 ,这样就不会耗时了

异步遍历

我们都知道同步遍历器是部署在对象的Symbol.iterator的属性上的,但是异步遍历器是部署在对象的Symbol.asyncIterator属性上的
以下代码是一个异步遍历器的例子

const asyncIterable = createAsyncIterable(['a', 'b']);
const asyncIterator = asyncIterable.Symbol.asyncIterator();
asyncIterator
.next()
.then(iterResult1 => {
  console.log(iterResult1); // { value: 'a', done: false }
  return asyncIterator.next();
})
.then(iterResult2 => {
 console.log(iterResult2); // { value: 'b', done: false }
 return asyncIterator.next();
})
.then(iterResult3 => {
  console.log(iterResult3); // { value: undefined, done: true }
});

从上面可以看出异步遍历器调用next方法返回一个promise,然后promise的状态变为resolve,然后调用then函数,执行then函数内的回调函数
由于调用next方法返回的是一个promise对象,所以说可以放在await命令后面,代码如下

async function f() {
 const asyncIterable = createAsyncIterable(['a', 'b']);
 const asyncIterator = asyncIterableSymbol.asyncIterator;
 console.log(await asyncIterator.next());
  // { value: 'a', done: false }
  console.log(await asyncIterator.next());
 // { value: 'b', done: false }
 console.log(await asyncIterator.next());
 // { value: undefined, done: true }
}

上面的代码接近于同步执行,但是我们想要所有的await基本上同时进行,可以有一下俩种表示

const asyncGenObj = createAsyncIterable(['a', 'b']);
const [{value: v1}, {value: v2}] = await Promise.all([
 asyncGenObj.next(), asyncGenObj.next()
]);
console.log(v1, v2); // a b
//第二种
async function runner() {
  const writer = openFile('someFile.txt');
 writer.next('hello');
 writer.next('world');
 await writer.return();
}
runner();

for await of

我们都知道同步遍历器我们可以使用for of来遍历,但是异步的遍历器,我们使用for await of来遍历

async function f() {
for await (const x of createAsyncIterable(['a', 'b'])) {
 console.log(x);
  }
}
// a
// b

异步generator函数

简单的说就是async与generator函数的结合,如下

async function* gen() {
  yield 'hello';
}
const genObj = gen();
genObj.next().then(x => console.log(x));
// { value: 'hello', done: false }

首先genObj.next()返回的是一个promise,然后调用then,执行then里面的函数,再看一个我认为比较重要的例子

async function* readLines(path) {
let file = await fileOpen(path);
try {
  while (!file.EOF) {
  yield await file.readLine();
}
} finally {
  await file.close();
}
}

我们可以看出异步generator函数,既有await也有yield,其中await命令用于将file.readLine()返回的结果输入到函数内,然后yield用于将输入到函数内的结果从函数输出


在异步generator函数中的yield* 语句后面还可以跟一个异步的generator函数

你可能感兴趣的:(async函数)