V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
selfcreditgiving
V2EX  ›  JavaScript

一个 async function 数组, 怎样一个一个顺序执行?

  •  
  •   selfcreditgiving · 2021-10-23 16:14:56 +08:00 · 3308 次点击
    这是一个创建于 1128 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想做到的是,每过一秒,分别打印:
    this is 0
    this is 1
    this is 2
    ~
    this is 8

    下面的代码结果是过一秒后全部执行。

    是不是哪里写的不对呢,多谢指教

    var jobs = [];
    
    for(let i = 0; i < 8; i++) {
        jobs.push(async function(){
            setTimeout(function(){
                console.log("this is " + i)
            },1000)
        });
    }
    
    (async function () {
        for (const job of jobs) {
            await job()
        }
            
    })();
    
    20 条回复    2021-10-27 13:39:28 +08:00
    ruxuan1306
        1
    ruxuan1306  
       2021-10-23 16:18:39 +08:00
    ```
    const job = new Promise((resolve, reject) => {
    setTimeout(() => resolve, 3000)
    })

    console.log('start')
    await job()
    console.log('done')
    ```
    ruxuan1306
        2
    ruxuan1306  
       2021-10-23 16:20:08 +08:00
    async 只是 promise 的语法糖,await 本质上必须等待一个 promise ,如果 await 一个立即数,则会立即 resolve 。
    setTimeout 返回的是 timer 的 id ,是一个立即数,所以会立即 resolve ,你必须返回一个 promise 。
    codehz
        3
    codehz  
       2021-10-23 16:21:03 +08:00
    var jobs = [];

    for(let i = 0; i < 8; i++) {
    jobs.push(() => new Promise(resolve => setTimeout(() => {
    console.log("this is " + i);
    resolve();
    },1000)));
    }

    (async function () {
    for (const job of jobs) {
    await job()
    }
    })();
    MonkeyD1
        4
    MonkeyD1  
       2021-10-23 16:21:17 +08:00
    var jobs = [];

    for (let i = 0; i < 8; i++) {
    jobs.push(async function () {
    return new Promise(function (resolve, reject) {
    setTimeout(function () {
    resolve(console.log("this is " + i));
    }, 1000);
    });
    });
    }

    (async function () {
    for (const job of jobs) {
    await job();
    }
    })();
    MonkeyD1
        5
    MonkeyD1  
       2021-10-23 16:22:33 +08:00
    return promise
    Curtion
        6
    Curtion  
       2021-10-23 16:23:06 +08:00
    你得这样
    ```javascript
    var jobs = [];

    for(let i = 0; i < 8; i++) {
    jobs.push(async function(){
    return new Promise(resolve => {
    setTimeout(function(){
    console.log("this is " + i)
    resolve()
    },1000)
    })
    });
    }

    (async function () {
    for (const job of jobs) {
    await job()
    }

    })();
    ```
    ruxuan1306
        7
    ruxuan1306  
       2021-10-23 16:23:48 +08:00
    发现我代码里 resolve 漏了对括号,会导致无人调用 resolve 无限等待,我猜你应该明白该怎么改正。
    selfcreditgiving
        8
    selfcreditgiving  
    OP
       2021-10-23 16:29:52 +08:00
    @ruxuan1306 @codehz @MonkeyD1 多谢多谢 一下就解决了,v 友圈厉害了
    0Vincent0Zhang0
        9
    0Vincent0Zhang0  
       2021-10-23 16:37:35 +08:00 via Android
    把 1000 改为 (i+1)*1000 [doge]
    kaixuan1901
        10
    kaixuan1901  
       2021-10-23 17:12:14 +08:00
    ```javascript
    function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
    }

    (async function() {
    for (let i = 0; i < 8; i++) {
    await sleep(1000);
    console.log("This is " + i);
    }
    })();
    ```
    wakaka
        11
    wakaka  
       2021-10-23 22:47:31 +08:00
    好好理解一下 promise
    selfcreditgiving
        12
    selfcreditgiving  
    OP
       2021-10-24 00:33:09 +08:00
    @0Vincent0Zhang0 呵呵 这个头比较铁 :)
    beyondstars
        13
    beyondstars  
       2021-10-24 14:37:21 +08:00
    function makeAsyncFunc(outputNum) {
    return async function () {
    const now = new Date().valueOf();
    console.log(`${now}: this is ${outputNum}`);
    };
    }

    const funcs = [];
    for (let i = 1; i <= 10; i++) {
    funcs.push(makeAsyncFunc(i));
    }

    function execOneByOne(asyncFuncs) {
    if (asyncFuncs.length === 0) {
    return;
    }

    const currentFunc = asyncFuncs.shift();
    currentFunc().then(() => {
    setTimeout(() => execOneByOne(asyncFuncs), 1000);
    });
    };

    execOneByOne(funcs);

    思路是把任务调度和任务执行区分开。
    xingguang
        14
    xingguang  
       2021-10-25 10:07:36 +08:00
    我看问题已经解决了,但是我稍微吐槽一下:var 和 let 混用让略微有点强迫症的我看着有点难受。
    danhua
        15
    danhua  
       2021-10-25 15:24:19 +08:00
    我的想法是可不可以用微任务和宏任务来解释这个。
    wangtian2020
        16
    wangtian2020  
       2021-10-25 17:29:16 +08:00
    ```
    let i = 0
    let prm = () => new Promise((resolve, reject) => {
    setTimeout(() => {
    console.log(i++);
    resolve()
    }, 1000)
    }
    )


    ; (async () => {
    await prm()
    await prm()
    await prm()
    await prm()
    await prm()
    await prm()
    })()
    ```
    注意,settimeout 1000 代表着一定会在 1000 毫秒之后返回,可能是 1001 毫秒,1010 毫秒,如果内部同步卡住 2000 毫秒都有可能。
    photon006
        17
    photon006  
       2021-10-26 09:20:56 +08:00
    把 setTimeout 封装成 delay 方法,放到 for 外边当成 utils 工具使用,for 改成 for await 串行执行,在 for await 内调用 delay()。
    chenjiangui998
        18
    chenjiangui998  
       2021-10-26 14:58:06 +08:00
    let jobs = []
    for (let i = 0; i < 10; i++) {
    let a = i
    jobs.push(async () => {
    console.log('this is', a)
    })
    }

    let time = setInterval(() => {
    if (jobs.length) {
    jobs.shift()()
    } else {
    clearInterval(time)
    }
    }, 1000)

    和异步不异步没有关系
    2i2Re2PLMaDnghL
        19
    2i2Re2PLMaDnghL  
       2021-10-27 00:40:34 +08:00
    @danhua 无关,而是顺次执行 setTimeout ,根本没等回调返回就先去找下一个去了,是逻辑错误而不是机制问题。
    async function 里面没有 await 会立刻变为 fulfilled ,await 可能不会发生调度?
    cenbiq
        20
    cenbiq  
       2021-10-27 13:39:28 +08:00
    @danhua 这恐怕只是没搞懂 js async/await 原理
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1128 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 18:19 · PVG 02:19 · LAX 10:19 · JFK 13:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.