bibi7 / fe-daily-increase

一个记录开发日常和奇奇怪怪的点的repo
MIT License
5 stars 0 forks source link

async #26

Open bibi7 opened 5 years ago

bibi7 commented 5 years ago

related to #15

其实除了异步两个字以外也没啥关联。。。 大部分都是api相关基础知识,摘自阮一峰

bibi7 commented 5 years ago

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);

async有两个特点:

  1. async本身会立即返回一个pending状态的promise
  2. 遇到await的时候,除非await执行完毕,否则async函数是处于暂停的状态。

async 函数有多种使用形式:

// 函数声明
async function foo() {}

// 函数表达式
const foo = async function () {};

// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)

// Class 的方法
class Storage {
  constructor() {
    this.cachePromise = caches.open('avatars');
  }

  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}

const storage = new Storage();
storage.getAvatar('jake').then(…);

// 箭头函数
const foo = async () => {};

简化的sleep实现:

function sleep(interval) {
  return new Promise(resolve => {
    setTimeout(resolve, interval);
  })
}

// 用法
async function one2FiveInAsync() {
  for(let i = 1; i <= 5; i++) {
    console.log(i);
    await sleep(1000);
  }
}

one2FiveInAsync();

主要想讲的还是另一个问题,为什么forEach中不能使用async?

var multi = num => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(num * num)
    }, 1000)
  })
}

async function test () {
  var nums = [1,2,3]
  nums.forEach(async x => {
    var res = await multi(x)
    console.log(res)
  })
}
test()

期望的打印是每隔一秒打印一个数字,但是现在获得的结果是等了一秒一起输出结果。

在本例中 forEach 的回调函数是一个异步函数,异步函数中包含一个 await 等待 Promise 返回结果,我们期望数组元素串行执行这个异步操作,实际上是并行执行。

forEach 的 polyfill 参考:MDN-Array.prototype.forEach(),简单点理解:

Array.prototype.forEach = function (callback) {
  // this represents our array
  for (let index = 0; index < this.length; index++) {
    // We call the callback for each entry
    callback(this[index], index, this)
  }
}
//相当于是for循环并行执行了异步函数

说白了就是,虽然callBack是一个具有await的异步调用,但是这一堆callback本身是同步执行

既然这样,要改造其实就有点思路了,比如可以直接让forEach确保每一个回调执行后再执行下一个:

Array.prototype.forEachAsync = async function (callback) {
  for (let index = 0; index < this.length; index++) {
        await callback(this[index], index, this)
  }
}

可以采用内部基于迭代器的for of形式代替:

async function test () {
  var nums = [1,2,3]
  for (let num of nums) {
    var res = await multi(num)
    console.log(res)
  }
}

api版本,新增了Promise.all的方式(这个我倒是没试过

Array.prototype.forEachAsync = async function (fn) {
    for (let t of this) { await fn(t) }
}

Array.prototype.forEachAsyncParallel = async function (fn) {
    await Promise.all(this.map(fn));
}
bibi7 commented 4 years ago
async function async1(){
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2(){
    console.log('async2')
}
console.log('script start')
setTimeout(function(){
    console.log('setTimeout') 
},0)  
async1();
new Promise(function(resolve){
    console.log('promise1')
    resolve();
}).then(function(){
    console.log('promise2')
})
console.log('script end')

关于这道题,promise2async1 end在不同的浏览器环境,不同的v8版本之间都会有先后不同的表现。 具体原因可见: async/await 在chrome 环境和 node 环境的 执行结果不一致,求解?