await实现并发的原理

await处理异步的时候,每执行到await就会跳出其所在的async函数,等到await有了结果(resolve或者reject)才会回到async函数继续执行。也就是说async内的await使继发的,那么如何用await实现并发呢?
例如我想读取两个文件,由于这两个文件之间没有依赖关系,我想并发读取

var fs=require('fs');
var read=function (path) {
    return new Promise((resolve,reject)=>{
            fs.readFile(path,(err,data)=>{
                if(err){
                    reject(err)
                }else{
                    resolve(data)
                }
            })
    })
}
//继发读取
async function ReadTwo(){
    var f1=await read('./a.txt');
    var f2=await read('./b.txt');
}

第一种办法使利用Promise.all

async function readTwo{
	var p=Promise.all([read('./a.txt'),read('./b.txt')]);
	var [f1,f2]=await p
}

第二种办法

async function readTwo{
	var p1=read('./a.txt');
	var p2=read('./a.txt');
	f1=await p1;
	f2=await p2;
}

为什么这样就是并发呢?明明还是两个await啊?
因为readFile本身是非阻塞的!p1=read(’./a.txt’)是把一个promise对象赋给p1,不会停在这里等待他的执行结果,而p1=await read(’./a.txt’)是把promise的执行结果赋给p1,在promise有结果之前不会执行赋值操作。
async内部代码在promise返回结果之前会阻塞住,但整个主线程不会阻塞,而是会执行async函数后面的同步代码。等promise有了结果且外面的同步代码执行完了就又会回到async函数原来阻塞的地方继续执行。

分析:

var p1=read('./a.txt')

这一行会把读取a.txt的任务交给文件读取模块(nodejs的异步I/O),然后立即执行下一句var p2=(’./b.txt’),立即把读取b.txt的任务交给文件读取模块 ,这时我们的计算机就同时在读取a.txt和b.txt啦。后面的await跟继发一样在等待文件读取的结果,不同的是,这次两个文件同时在读取。也就是说读取文件是并行的,只不过读取结果的赋值是继发的。

补充:数组的map,foreach等方法的参数函数是async的情况
这个例子出自阮一峰老师《ES6入门》,目的是实现并发获取一组url的数据,然后将获取到的结果顺序输出。

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的,map的函数参数是async 的。
map可以看作一个循环,下一个循环并不会等待上一个循环有了结果才去执行,每个循环执行到await时,会把远程获取数据的任务交给http模块,然后立即执行下一次循环。至于每个循环体内部未执行完的语句,哪个url先得到结果就先执行哪个。也就是说,内层的await只会阻塞内层,不会阻塞外层。
由于map内部的await不会阻塞map外部代码,那么当url还没有返回结果的时候,就已经执行到了下面的for语句,所以在输出textPromise时需要await,这样可以保证获取到的数据是按照原来url数列的顺序输出的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值