使用 async / await 实现 setTimeout 的同步写法

文章目录

    在 tampermonkey 的很多实际使用场景中,需要在模拟点击之后,等待界面变化,或者数据返回,此时就需要用到 setTimeout。但是如果是一系列的点击等待,就需要进行 setTimeout 嵌套,或者 setTimeout 时间进行倍数增长,代码可读性非常低。

    所以,我想找一种 setTimeout 同步的写法,以提高代码的可维护性。

    测试代码

    (function() {
        'use strict';
    
        function wait(ms) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log("Done waiting");
                    resolve(ms)
                }, ms)
            })
        }
    
        (async () => {
            console.log("Starting...")
            await wait(5000);
            console.log("Ended!")
    
            for (var i = 0, len = 6; i < len; i++) {
                console.log("loop " + i);
                await wait(2000);
            }
    
        })();
    
        console.log("end");
    })();
    

    在 tampermonkey 中的运行结果:

    Starting...
    end
    Done waiting
    Ended!
    loop 0
    Done waiting
    loop 1
    Done waiting
    loop 2
    Done waiting
    loop 3
    Done waiting
    loop 4
    Done waiting
    loop 5
    Done waiting
    

    完全符合预期,以后写 setTimeout 就不用嵌套那么多层了。

    Uncaught SyntaxError: await is only valid in async function

    注意 await 只能在 async 函数中使用,否则会报错:

    Uncaught SyntaxError: await is only valid in async function

    async / await 的字面意思

    • async 是 asynchronous 的缩写,即异步
    • await 是等待、等候的意思。但是这个单词与 wait 的区别是什么?https://ell.stackexchange.com/questions/8207/what-is-the-difference-between-wait-and-await

    async / await 的使用方法

    • async 用来标注一个函数为异步函数
    • await 只能在 async 异步函数中使用;但是 async 函数可以不包含 await 操作
    • 在 async 函数中,await 起到了阻塞(同步执行)的作用
    • 一个 async 函数中,可以有多行 await 语句
    • await 需要等待一个 Promise
    • promise 代表一个异步操作的开始
    • 异步函数与普通函数的调用方法一样,没有区别
    • async 函数返回 promise,如果 return 的值不是 promise,会被自动转换成 promise

    参考 MDN 上的示例:

    function resolveAfter2Seconds() {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve('resolved');
        }, 2000);
      });
    }
    
    async function asyncCall() {
      console.log('calling');
      const result = await resolveAfter2Seconds();
      console.log(result);
      // expected output: "resolved"
    }
    
    asyncCall();
    

    为何要使用 Promise

    A Promise is an object representing the eventual completion or failure of an asynchronous operation.

    await 的下一行代码,只有当 await 等待的 promise 被 resolve,才能被执行。

    async / await 的兼容性问题

    async / await 是 ES7 进入的,即 ECMAScript 17。

    参考

    • https://stackoverflow.com/questions/6921895/synchronous-delay-in-code-execution
    • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
    • https://medium.com/better-programming/should-i-use-promises-or-async-await-126ab5c98789
    • https://itnext.io/javascripts-async-await-versus-promise-the-great-debate-6308cb2e10b3

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式