Skip to content

第 9 题:Async/Await 如何通过同步的方式实现异步 #156

@yygmind

Description

@yygmind
Contributor
No description provided.

Activity

chenzesam

chenzesam commented on Jul 9, 2019

@chenzesam

no body?

wdzyy

wdzyy commented on Jul 9, 2019

@wdzyy

where is dalao?

xzzdll

xzzdll commented on Jul 9, 2019

@xzzdll

Async/Await 其实是generate函数的语法糖,想搞清楚用同步的方式实现异步只要搞清generate函数内部的机制就好了,不知道对不对- -

shizhihua666

shizhihua666 commented on Jul 9, 2019

@shizhihua666

Async/Await本来就是异步,那有同步可言

xzzdll

xzzdll commented on Jul 9, 2019

@xzzdll

@shizhihua666 以同步的方式实现异步,不是说他是同步

hiblacker

hiblacker commented on Jul 9, 2019

@hiblacker

这个应该是考察基本使用

function getFoo(){
  return new Promise(resolve => setTimeOut( () => resolve('foo') , 1000))
}
async function asyncFn(){
  let foo = await getFoo()
  let logic = '同步是加引号的'
}
NathanHan1

NathanHan1 commented on Jul 9, 2019

@NathanHan1

Async/Await就是一个自执行的generate函数。利用generate函数的特性把异步的代码写成“同步”的形式。

var fetch = require('node-fetch');

function* gen(){  // 这里的*可以看成 async
  var url = 'https://api.github.com/users/github';
  var result = yield fetch(url);  // 这里的yield可以看成 await
  console.log(result.bio);
}
var g = gen();
var result = g.next();

result.value.then(function(data){
  return data.json();
}).then(function(data){
  g.next(data);
});

具体见这里

YOMXXX

YOMXXX commented on Jul 10, 2019

@YOMXXX

async await 用于把异步请求变为同步请求的方式,第一个请求的返回值作为后面一个请求的参数,其中每一个参数都是一个promise对象
例如:这种情况工作中会经常遇到

(async () => {
    var a = await A();
    var b = await B(a);
    var c = await C(b);
    var d = await D(c);
})();

setTimeout 主要用户异步队列的形式,当然其中又分为宏观队列以及微观队列(Promise.then,process.nextTick等),比如隔1000ms执行一段逻辑代码(实际中不一定是1000ms后执行,需要考虑主任务的执行时间)

console.log(1);
setTimeout(() => {
    console.log(2)
}, 0)
setTimeout(() => {
    console.log(3)
}, 1000)
new Promise(resolve => {
    console.log(4)
    resolve()
}).then(() => {
    console.log(5)
})
nenezsn

nenezsn commented on Jul 10, 2019

@nenezsn

@shizhihua666 厉害啊 兄弟

arcsin1

arcsin1 commented on Jul 10, 2019

@arcsin1

应该是下面这张写法吧(链式):

Promise.resolve().then(() => {
    console.log(1111)
}).then(() => {
    console.log(2222)
}).then(() => {
    console.log(3333)
})
 //  111, 222,333
liuliudaren

liuliudaren commented on Jul 11, 2019

@liuliudaren

where is dalao?

U waiyu good

cooldrangon

cooldrangon commented on Jul 12, 2019

@cooldrangon

可以参考你不知道的js一书的中册里面的生成器与迭代器章节看看

iamwelk

iamwelk commented on Jul 13, 2019

@iamwelk

题目是不是应该改成“如何通过异步的方式实现同步”?

cooldrangon

cooldrangon commented on Jul 13, 2019

@cooldrangon

29 remaining items

fanzye95th

fanzye95th commented on Aug 20, 2020

@fanzye95th

where is dalao?you are yincai

matthew-maozhu-wang

matthew-maozhu-wang commented on Sep 7, 2020

@matthew-maozhu-wang

老实说,await如何通过同步的方式实现异步不是因为await之后的所有语句都会被放到微任务队列吗?个人觉得解释async/await的时间原理什么的肯定是更好,但是他为什么“同步”了,就是因为他在执行上把await之后的语句都“异步”了,保证了await之后的语句都在await的回调之后执行吧。(小白乱说的)

mengshis

mengshis commented on Sep 16, 2020

@mengshis

async基础技术使用了生成器和promise,生成器是协程的实现,利用生成器实现生成器函数的暂停和恢复。
async是通过异步调用并隐式返回promise所为结果的函数。
await会默认创建一个promise对象。

flftfqwxf

flftfqwxf commented on Dec 2, 2020

@flftfqwxf

我想问问,这个题目是要解决的是什么问题?

AKclown

AKclown commented on Dec 26, 2020

@AKclown
this._head.element = this._head.next;

  // 删除第一个匹配到的节点
  remove(element) {
    if (this._size < 1) return null;

    if (this._head.element == element) {
      this._head.element = this._head.next;
      this._size--;
      return element;
    } else {
      let temp = this._head;
      while (temp.next) {
        if (temp.next.element == element) {
          temp.next = temp.next.next;
          this._size--;
          return element;
        } else {
          temp = temp.next;
        }
      }
    }
    return null;
  }

this._head.element = this._head.next; 是不是应该改为 this._head = this._head.next; 才对呢

passing-j

passing-j commented on Jan 5, 2021

@passing-j

async/await 组合可以像写同步代码那样写异步代码。比如有 3 个 ajax 请求,每个请求都依赖上一个的结果,可以写成:

function st(time, value) {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log('等待%d秒', time/1000)
            value && console.log(value)
            resolve()
        }, time)
    })
}
async function syn() {
    await st(3000)
    await st(1000, '拿到步骤1的结果')
    await st(2000, '拿到步骤2的结果')
}
syn()
wensiyuanseven

wensiyuanseven commented on Feb 21, 2021

@wensiyuanseven
       const readFile = function (fileName) {
            return new Promise(function (resolve, reject) {
                setTimeout(() => {
                    resolve(fileName)
                }, 1000)
            });
        };

        const gen = function* () {
            const f1 = yield readFile('/etc/fstab');
            const f2 = yield readFile('/etc/shells');
            console.log(f1);
            console.log(f2);
        };
        // 手动执行代码
        // var g = gen();
        // g.next().value.then(function (data) {
        //     g.next(data).value.then(function (data) {
        //         g.next(data);
        //     });
        // });

        // 自动执行代码
        function run(gen) {
            var g = gen()
            function next(data) {
                var result = g.next(data)
                // 结束执行
                if (result.done) return
                result.value.then(function (data) {
                    next(data)
                });
            }
            next();
        }
        run(gen);
shifengdiy

shifengdiy commented on Jul 29, 2021

@shifengdiy

async awit 就是 promise.then的语法糖

const promiseF = function(){
  return  new Promise((resolve) => {
      setTimeout(() =>{
        resolve('done')
      }, 100)
    })
}

const asyncF = async function(){
  console.log(1)
  await promiseF();
  console.log(2)
}

等同于

const asyncF2 = async function(){
  console.log(1) 
  Promise.resolve(promiseF()).then(res => {
    console.log(2)
  })
}

注意
理论上 await 之后必须是一个promise对象,如果await之后是一个普通函数执行或者对象,会被包装成一个promise对象

lazyhero

lazyhero commented on Aug 18, 2021

@lazyhero

我想问问,这个题目是要解决的是什么问题?

应该是想问 async/await (Generator)的实现,面试官期望你答出实现、场景(什么时候用await什么时候不用)和坑点,毕竟自古以来JS花活第一名,你可能不这么耍,但可能面试官觉得如果有人耍了花活,你要知道他耍的对不对,有哪些坑;

Qyokizzzz

Qyokizzzz commented on Dec 6, 2021

@Qyokizzzz

function fn1() {
return new Promise((resolve, reject) => {
fn2()
.then((res) => res.method())
.then((res) => resolve(res.property));
})
}

async function fn1() {
let p1 = await fn2();
let p2 = await p1.method();
return p2.property;
}

两个fn1等价。
async函数的返回值是一个Promise,await可以让代码看起来像同步。

NAZBIN

NAZBIN commented on Feb 27, 2022

@NAZBIN

看到没有好的答案,自己提炼总结一下。

Async/awiat诞生的背景:使用promise能很好的解决回调地狱的问题,但是这种充满了.then()方法,如果处理流程复杂,那么整段代码有很多then,会导致语义化不明确。

Async/await使用了两种技术:Promise和Generator(底层实现机制——协程)

生成器运行过程:生成器Generator是可以暂停执行和恢复执行的。可能还有人对生成器这块不理解,简单说一下:
在生成器函数内部执行一段代码,遇到yield关键字,js引擎会返回关键字后面的内容给外部,并暂停该函数的执行。外部函数可以通过next方法恢复函数的执行。

V8层面抛析暂停与恢复的实现原理:要搞懂函数为什么能暂停和恢复,首先要了解协程的概念。简单来说,可把协程看成是跑在线程上的任务,线程与协程之间是'1 v N'的关系,但是在线程上同一时间只能执行一个协程任务,比如当前执行的是A协程,要启动B的话A就需要将控制权交给B,这就体现在A暂停执行,B恢复执行,我们把A叫做B的父协程。

协程的高效性:协程是完全由程序所控制,也就是在用户态执行,这样的好处就是性能得到了很大的提升,不会像切换线程那样消耗资源。

(上面只是简单描述了协程的执行过程,其实中间还涉及到协程的调用栈切换以及协程的信息返回等等,感兴趣可以再交流)

那在JS中,生成器就是协程的一种实现方式,相信你也理解什么是生成器了。 推荐大家用Generator生成器和Promise来模拟一下async和await的实现。

通过使用生成器配合执行器,就能实现使用同步的方式写出异步代码。基本说到这已经解答了这个问题,中间过程上面的问题 可以再交流。

Yangfan2016

Yangfan2016 commented on Aug 22, 2022

@Yangfan2016

generator 实现的
image

eric-gitta-moore

eric-gitta-moore commented on Jan 26, 2024

@eric-gitta-moore

感觉 generator + Iterator + promise 这么理解似乎没问题,但是具体实现是这么弄得嘛,还是另有道路。google v8、spidermonkey、JavaScript core 都是这么弄的嘛也不太清楚,各个 js engine 的各个版本又是怎么实现的,有没有出入也不太清楚

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @flftfqwxf@iamwelk@yft@ZangYuSong@gooqiao

        Issue actions

          第 9 题:Async/Await 如何通过同步的方式实现异步 · Issue #156 · Advanced-Frontend/Daily-Interview-Question