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

更新日期: 2021-01-31 阅读次数: 16632 字数: 569 分类: Javascript

在 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 聊聊, 查看更多联系方式