进阶学习 Javascript ? 来看看这篇系统复习笔记 [ Promise 与 async 篇 ]

Javascript Promise 与 async

  • Javascript 编程语言
    • Javascript 基础知识
    • Javascript 更多引用类型
    • Javascript 引用类型进阶知识
    • Javascript 函数进阶知识
    • Javascript 面向对象
    • Javascript 错误处理
    • Javascript 生成器 Generator
    • Javascript Promise与async
    • Javascript 模块 Module
  • Javascript 浏览器

回调

回调方法的简介

回调函数是 JavaScript 中处理异步操作的传统方式,它是指作为参数传递给另一个函数并在特定条件满足时被调用的函数。

JavaScript 环境提供了许多使用回调函数的 API:

  • setTimeout(callback, delay):延迟执行回调函数。
  • setInterval(callback, interval):定期执行回调函数。
  • 事件处理器:如addEventListener(event, callback)监听事件,执行回调。
  • Array 方法:如 forEachmapfilter 等方法,数组遍历回调。
  • Promise 对象:如 .then(callback) 方法,在Promise 执行成功后回调。

示例:插入一个脚本的函数

js 复制代码
// 将动态创建的标签 <script src="..."> 插入到文档中
function loadScript(src, callback) {
    let script = document.createElement('script');
    script.src = src;
    
    script.onload = () => callback(null, script);
    script.onerror = () => callback(new Error(`脚本加载失败: ${src}`));
    
    document.head.append(script);
}

// 使用回调函数
loadScript('path/to/script.js', (error, script) => {
    if (error) {
        console.error('加载错误:', error);
    } else {
        console.log('脚本加载成功:', script.src);
        // 可以在这里使用加载的脚本中的功能
    }
});

JavaScript 社区形成了"错误优先回调"(Error-first Callback)的约定:

  1. 回调函数的第一个参数保留给错误对象
  2. 后续参数用于传递成功时的结果
  3. 成功时第一个参数传 nullundefined

回调地狱

在回调中回调,则代码向右不断延伸,形成"金字塔"形状;

这种情况下,错误处理重复且冗长,代码可读性和可维护性差,难以追踪执行流程;

因此,这种情况被称为回调地狱

js 复制代码
loadScript('script1.js', (err, script1) => {
    if (err) {
        console.error(err);
    } else {
        loadScript('script2.js', (err, script2) => {
            if (err) {
                console.error(err);
            } else {
                loadScript('script3.js', (err, script3) => {
                    if (err) {
                        console.error(err);
                    } else {
                        // 所有脚本加载完成
                        startApplication();
                    }
                });
            }
        });
    }
});

解决方案

  1. 命名函数解耦

    js 复制代码
    function loadScript1(err) {
        if (err) return console.error(err);
        loadScript('script2.js', loadScript2);
    }
    
    function loadScript2(err) {
        if (err) return console.error(err);
        loadScript('script3.js', loadScript3);
    }
    
    function loadScript3(err) {
        if (err) return console.error(err);
        startApplication();
    }
    
    loadScript('script1.js', loadScript1);
  2. 使用 Promise

Promise

Promise 是 JavaScript 中处理异步操作的核心对象,它提供了一种更优雅的方式来处理异步编程。

基本语法结构

  1. 创建 Promise :使用 Promise 对象的构造器:

    js 复制代码
    let promise = new Promise(function(resolve, reject) {
      // executor(代码,"制作者")
      ...
      // 1 秒后发出工作已经被完成的信号,并带有结果 "done"
      setTimeout(() => resolve("done"), 1000);
    });
    • 传递给 new Promise 的函数被称为 executor
    • executor 包含两个由 JavaScript 引擎提供的回调函数:
      • resolve(value) - 表示操作成功完成
      • reject(error) - 表示操作失败
    • executor 运行结束后,如果成功则调用 resolve,如果出现 error 则调用 reject
  2. Promise 内部属性

    • 状态state

      状态 描述 触发条件
      pending 初始状态,既不是成功也不是失败状态 创建 Promise 时的初始状态
      fulfilled 操作成功完成 调用 resolve()
      rejected 操作失败 调用 reject()
    • result ------ 最初是 undefined,然后在 resolve(value) 被调用时变为 value,或者在 reject(error) 被调用时变为 error

    • 结果result

      状态 描述
      undefined 创建 Promise 时的初始状态
      value resolve(value) 被调用时变为 value
      error reject(error) 被调用时变为 error

      Promise 对象的 stateresult 属性都是内部的,无法直接访问,但可对它们使用 .then/.catch/.finally 方法。

  3. then 方法

    • 第一个参数是一个函数,该函数将在 promise resolved 且接收到结果后执行。

    • 第二个参数也是一个函数,该函数将在 promise rejected 且接收到 error 信息后执行。

      js 复制代码
      promise.then(
        function(result) { /* 处理成功结果 */ },
        function(error) { /* 处理错误 */ }
      );
    • then 可以返回一个值,该值会传递给下一个 then 处理程序。

      js 复制代码
      Promise.resolve("成功值")
        .then(result => {
          console.log("Then 收到:", result);
          return "新的值";
        })
        .then(result => {
          console.log("下一个 Then 收到:", result);  // 收到 "新的值"
        });
  4. catch 方法

    • 若只对 error 感兴趣,那可以用 null 作为then的第一个参数;.catch().then(null, errorHandler) 的简写形式

      js 复制代码
      let promise = new Promise((resolve, reject) => {
        setTimeout(() => reject(new Error("Whoops!")), 1000);
      });
      
      // .catch(f) 与 promise.then(null, f) 一样
      promise.catch(error => console.error(error)); // 1 秒后显示 "Error: Whoops!"
    • catchthen 一样,可以返回值,传给下一个 then 处理程序。

    • catch 也可以抛出错误,传给下一个 catch 处理程序。

      js 复制代码
      Promise.reject("错误A")
        .catch(err => {
          if (err === "错误A") {
            throw new Error("升级为错误B");
          }
          return "普通处理";
        })
        .catch(err => {
          console.log("捕获:", err.message); // "捕获: 升级为错误B"
          return "最终处理结果";
        })
        .then(result => {
          console.log(result); // "最终处理结果"
        });
  5. finally 方法:无论 Promise 成功或失败都会执行,执行清理/终结

    • finally 不会得到前一个处理程序的结果(它没有参数);如有结果,则该结果会被传递给了下一个合适的处理程序。

    • finally不应该返回任何内容;若返回内容则会被忽略。

      js 复制代码
      Promise.resolve("成功值")
        .finally(arg => {
          console.log("Finally 收到:", arg); // undefined
          return "finally 返回值"
        })
        .then(result => {
          console.log("下一个 Then 收到:", result);  // "成功值"
        });
    • finally 抛出 error 时会覆盖之前的 error,同时会中断传递,执行将转到最近的 error 的处理程序。

      js 复制代码
      // 案例1: 从成功状态抛出错误
      Promise.resolve("成功值")
        .finally(() => {
          throw new Error("finally中的错误");
        })
        .then(result => console.log("成功:", result))
        .catch(error => console.log("失败:", error.message));
      
      // 案例2: 从失败状态抛出错误
      Promise.reject(new Error("原始错误"))
        .finally(() => {
          throw new Error("finally中的新错误");
        })
        .catch(error => {
          console.log("捕获的错误:", error.message);  // 显示 finally中的新错误
        });

注意 ,一个 promise 内部在执行 resolvereject 后,并不会立即终止函数的执行。这是 Promise 设计的一个重要特性。

  • 避免不必要的执行中断开销
  • 允许在 resolvereject 后执行清理操作

但在 JavaScript 的 Promise 实现中,多次调用 resolvereject 是无效的,Promise 只会保持第一次调用的结果状态。

js 复制代码
new Promise((resolve, reject) => {
  console.log('1. Promise 构造函数开始执行');
  resolve('成功'); // 这里不会停止执行
  console.log('2. resolve 之后的代码仍然执行');
})
  .then(result => {
    console.log('3. then 回调执行:', result);
  });

如果不想执行 resolvereject 后的代码,可以使用 return 强行中断。

js 复制代码
new Promise((resolve, reject) => {
  return resolve('结果');
  console.log('这行不会执行'); 
});

Promise 链

Promise 链是 JavaScript 中处理异步操作的核心机制,它通过 .then() 方法将多个异步操作串联起来,形成清晰可读的代码结构。

每个 .then 的调用都会返回了一个新的 promise,因此我们可以在其之上调用下一个 .then

调用 .then() 时,根据返回值类型不同,会有不同的操作:

  • 返回普通值 → 自动包装为 resolved Promise
  • 返回 Promise → 等待其 settled
  • 返回 thenable 对象 → 按 Promise 处理
返回普通值

若有一系列的异步任务要一个接一个地执行,可创建一个 promise 链,它的想法是通过 .then 处理程序(handler)链进行传递 result。

js 复制代码
new Promise(resolve => {
  setTimeout(() => resolve(1), 1000);
})
.then(result => {
  console.log(result); // 1
  return result * 2;
})
.then(result => {
  console.log(result); // 2
  return result * 2;
})
.then(result => {
  console.log(result); // 4
});
返回 Promise

.then() 返回值是 Promise,则会在该 Promise 结束后才会触发下一次 .then

js 复制代码
new Promise(resolve => {
  setTimeout(() => resolve(1000), 1000);
})
  .then(result => {
    console.log("接收到毫秒数", result) // 接收到毫秒数 1000

    // 返回新Promise,将获取的 result 作为延迟执行的毫秒数
    return new Promise(resolve => {
      setTimeout(() => resolve("新 Promise"), result);
    });
  })
  .then(console.log) // "新 Promise"
返回 thenable 对象

确切地说,处理程序返回的不完全是一个 promise,而是返回的被称为 thenable 对象 ------ 一个具有方法 .then 的任意对象。它会被当做一个 promise 来对待。

第三方库可以实现自己的 promise 兼容(promise-compatible)对象 。它们可以具有扩展的方法集,但也与原生的 promise 兼容,因为它们实现了 .then 方法。

这个特性允许我们将自定义的对象与 promise 链集成在一起,而不必继承自 Promise

这是一个 thenable 对象的示例:

js 复制代码
class Thenable {
    constructor(num) {
       this.num = num;
    }
    then(resolve, reject) {
       alert(resolve); // function() { native code }
       // 1 秒后使用 this.num*2 进行 resolve
       setTimeout(() => resolve(this.num * 2), 1000); // (**)
    }
}

new Promise(resolve => resolve(1))
  .then(result => {
    return new Thenable(result); // (*)
  })
  .then(alert); // 1000ms 后显示 2

避免回调地狱

用 Promise 重写上一节中的示例 loadScript,避免回调地狱的产生。

js 复制代码
function loadScript(src){
    return new Promise()
      let script = document.createElement('script');
      script.src = src;
      
      script.onload = () => resolve(script);
      script.onerror = () => reject(new Error(`Error for ${src}`));
  
      document.head.append(script);
  });
}

loadScript("./tryLoad_1.js")
  .then(
    script => {
        alert(`${script.src} is loaded!`);
        return loadScript("./tryLoad_2.js");
    },
    error => alert(`Error:${error.message}`)
  )
  .then(script => alert(`${script.src} is loaded!`))
  .catch(error => alert(`Error:${error.message}`));

promise 错误处理

上文有初步介绍过 catch ,当一个 promise 被 reject 或抛出错误时,控制权将移交至最近的 错误处理程序。

  • 错误会沿着 Promise 链向下传播,直到遇到第一个 .catch() 处理程序
  • 如果没有 .catch(),则成为未处理的 rejection

正如所见,.catch 不必是立即的,它可能在一个或多个 .then 之后出现。

隐式 try...catch

promise 的 executor 周围的"隐式 try..catch"会自动捕获 error,并将其变为 rejected promise。

无论在 new Promise(()=>{}).then().catch() 还是 .finally 内抛出错误,都会转成类似如下面形式,最后交给下一个 错误处理程序。

js 复制代码
new Promise((resolve, reject) => {
  reject(new Error("Whoops!"));
}).catch(alert); // Error: Whoops!
未处理的 rejection

当发生一个常规的 error 并且未被 try..catch 捕获时,脚本会停止,并在控制台中留下了一个信息。对于在 Promise 中未被处理的 rejection,也会发生类似的事。

JavaScript 引擎会跟踪此类 rejection,在这种情况下会生成一个全局的 error

如果出现了一个 error,并且在这没有 .catch,那么 unhandledrejection 处理程序就会被触发,并获取具有 error 相关信息的 event 对象。

js 复制代码
// 浏览器环境
window.addEventListener('unhandledrejection', event => {
  console.error('未处理的Promise错误:', event.reason);
  event.preventDefault(); // 阻止默认错误输出
});

// Node.js环境
process.on('unhandledRejection', (reason, promise) => {
  console.error('未处理的Promise拒绝:', reason);
});

Promise 静态方法

立即返回结果
  1. Promise.resolve(value):创建一个立即 resolve 的 Promise:

    javascript 复制代码
    let resolvedPromise = Promise.resolve("立即解析的值");
    • 如果接收的是一个 promise ,那么仍然返回该 Promise 对象;如果接收的是一个普通值,那么就将其包装成 Promise 对象。

      js 复制代码
      const originalPromise = new Promise(resolve => resolve('结果'));
      
      const wrappedPromise = Promise.resolve(originalPromise);
      
      console.log(originalPromise === wrappedPromise); // true,是同一个对象
  2. Promise.reject(error):创建一个立即 reject 的 Promise:

    javascript 复制代码
    let rejectedPromise = Promise.reject(new Error("立即拒绝的错误"));
Promise.all( iterable )

Promise.all 的核心行为:

  • 接收一个可迭代对象(通常是 Promise 数组);该对象内也允许放入非 promise 的"常规"值。

  • 返回一个新的 Promise 对象

  • 当所有输入的 Promise 都成功时,返回结果数组;结果数组中元素的顺序与其在传入的类数组内顺序相同;

    js 复制代码
    function timePromise(contain, ms){
        return new Promise(
        	resolve => setTimeout(() => resolve(contain), ms)
        )
    }
    
    let arr = [
      timePromise(1, 3000),
      timePromise(2, 2000),
      3,
      "4",
      timePromise(5, 1000),
    ];
    
    Promise.all(arr).then(alert); // 1,2,3,4,5
  • 当任意一个 Promise 失败时,立即拒绝;返回结果变为该失败的 Promise 抛出的错误。

    js 复制代码
    let arr = [
      Promise.resolve(1),
      Promise.reject(new Error('失败')),
      2,
    ];
    
    Promise.all(arr).catch(alert); // Error: 失败

手动实现 Promise.all,其内部逻辑类似下面所写代码:

js 复制代码
Promise.myAll = function(promises) {
  return new Promise((resolve, reject) => {
    // 如果输入不是可迭代对象,直接reject
    if (!promises || typeof promises[Symbol.iterator] !== 'function') {
      return reject(new TypeError('Argument is not iterable'));
    }

    // 如果输入数组为空,直接resolve空数组
    if (promises.length === 0) {
      return resolve([]);
    }

    const results = new Array(promises.length);
    let completedCount = 0;

    promises.forEach((promise, index) => {
      // 确保每个元素都是Promise,如果不是则用Promise.resolve包装
      Promise.resolve(promise)
        .then(result => {
          results[index] = result;
          completedCount++;
          
          // 当所有Promise都完成时resolve结果数组
          if (completedCount === promises.length) {
            resolve(results);
          }
        })
        .catch(err => {
          // 任何一个Promise失败则立即reject
          reject(err);
        });
    });
  });
}

// 可用上文的案例数组进行测试
Promise.allSettled

Promise.allSettledPromise.all 功能类似。但Promise.allSettled 无论结果如何都会返回一个对应的结果数组,数组元素都是对象:

  • 成功的响应,结果数组对应元素:{status:"fulfilled", value:result}
  • 出现 error 的响应,结果数组对应元素:{status:"rejected", reason:error}
js 复制代码
let arr = [
  Promise.resolve(1),
  Promise.reject(new Error('失败')),
  2,
];

Promise.allSettled(arr).then(console.log).catch(console.log); // catch 不会运行

/* 结果如下:
[
 {status: 'fulfilled', value: 1},
 {status: 'rejected', reason: Error: 失败 at <anonymous>:3:18},
 {status: 'fulfilled', value: 2}
]

可以借助 Promise.all 来手动实现(当然这样操作消耗性能更多一点,可以直接修改上文写的 Promise.all 手动实现):

js 复制代码
// 定义处理器,接收 Promise 的成功或者失败结果
const rejectHandler = reason => ({ status: 'rejected', reason });
const resolveHandler = value => ({ status: 'fulfilled', value });

// 定义包装器,将传入数组内的元素全部包装成 Promise,并用 then 处理程序接收他们的结果,用定义的处理器装入相应的对象中
function convertedPromises(promises){
    return promises.map(p => Promise.resolve(p).then(resolveHandler, rejectHandler));
}

// 用 Promise.all 的形式返回结果
Promise.myAllSettled = function (promises) {
  const arr = convertedPromises(promises)
  return Promise.all(arr);
};

// 可用上文的案例数组进行测试
Promise.race

Promise.racePromise.all 功能类似。但 Promise.race 只等待第一个完成或出错的 promise 并获取其结果。

js 复制代码
let arr = [
  new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
  new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)),
  new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
];

Promise.race(arr).then(alert).catch(alert); // 1

手动实现 Promise.race,代码类似如下所写:

js 复制代码
// 为简化代码,默认传入的是数组
Promise.myRace = function(promises) {
  return new Promise((resolve, reject) => {
    if (promisesArray.length === 0) {
      return; // 永远pending,与原生行为一致
    }

    // 确保每个元素都是Promise
    for (const promise of promisesArray) {
      Promise.resolve(promise).then(resolve, reject); // 第一个完成的会触发外层Promise
    }
  });
};
Promise.any

Promise.any 则是 Promise.race 修改版。Promise.any 不会抛出错误,只等待第一个完成的 promise 并获取其结果。

js 复制代码
// 注意,这里是 Error 最先被抛出,但 catch 未被触发
let arr = [
  new Promise((resolve, reject) => setTimeout(() => resolve(1), 2000)),
  new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 1000)),
  new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
];

Promise.any(arr).then(alert).catch(alert); // 1

手动实现 Promise.any,代码类似如下:

js 复制代码
// 为简化代码,默认传入的是数组
Promise.myAny = function(promises) {
  return new Promise((resolve, reject) => {
    if (promisesArray.length === 0) {
      return reject(new AggregateError([], 'All promises were rejected'));
    }

    let rejectedCount = 0;
    const errors = new Array(promisesArray.length);

    promisesArray.forEach((promise, index) => {
      Promise.resolve(promise)
        .then(resolve) // 任何一个成功就立即解决
        .catch(err => {
          errors[index] = err;
          rejectedCount++;
          
          // 当所有Promise都拒绝时
          if (rejectedCount === promisesArray.length) {
            reject(new AggregateError(errors, 'All promises were rejected'));
          }
        });
    });
  });
};

超时控制

promise 中没有直接设置"取消"这一功能,需要借助其他方法来实现中止的操作。

AbortController可以帮助我们解决 ,但它不是 Promise API 的一部分。

js 复制代码
function timeoutPromise(fn, signal) {
  return new Promise((resolve, reject) => {
    // 如果信号已经中止,立即拒绝
    if (signal.aborted) {
      return reject(new DOMException('Aborted', 'AbortError'));
    }
    
    // 执行异步操作
    fn(resolve, reject);
    
    // 监听中止事件
    signal.addEventListener('abort', () => {
      reject(new DOMException('Aborted', 'AbortError'));
    });
  });
}

const controller = new AbortController();
const signal = controller.signal;
const task = timeoutPromise( resolve=>setTimeout( ()=>resolve(1), 1000 ) )
task
setTimeout(() => controller.abort(), 500); // 500ms后取消

也可以使用 Promise.race 来控制

javascript 复制代码
function withTimeout(promise, timeout) {
  return Promise.race([
    promise,
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error('超时')), timeout)
    )
  ]);
}

Promise.all([
  withTimeout(fetch('/api1'), 5000),
  withTimeout(fetch('/api2'), 5000)
])
.then(/* ... */);

更新的 Promise 方法

JavaScript 之后在 ES 规范中又提出了一些相对较新的提案。

Promise.withResolvers()

Promise.try() 是 ES2024 新增的 Promise 静态方法,简化了 Promise 的创建和管理,使异步编程更容易理解。

这个方法减少样板代码,避免了手动提取 resolve/reject 的繁琐过程,代码意图更加清晰明确。同时,解决了在某些情况下 resolve/reject 不在正确作用域的问题。

js 复制代码
function getWeather(city) {
  const { promise, resolve, reject } = Promise.withResolvers();

  // 模拟 API 调用
  setTimeout(() => {
    if (city === "New York") {
      resolve("Sunny, 75°F");
    } else {
      reject("City not found");
    }
  }, 2000);

  return promise;
}

// 使用该函数
getWeather("New York")
  .then(weather => console.log("Weather:", weather))
  .catch(error => console.log("Error:", error));
Promise.try()

Promise.try() 是 ES2025 新增的 Promise 静态方法,它提供了一种统一处理同步/异步函数的标准化方案。目前(2025-4-25),部分浏览器还未支持。

在实际开发中,我们经常遇到一种情况:有一个函数,我们不知道或不想区分它是同步还是异步,但又想用 Promise 来处理它。

Promise.resolve().then(f); 来包装这个函数,则会使其变成异步的,失去同步函数的特性。(同步、异步函数的具体区别在于 Javascript 事件循环特性)

Promise.try 让同步函数保持同步特性,在当前事件循环立即执行;异步函数也保持原有异步特性;让同步、异步代码具有统一的错误处理 API 。

Promise.try 与普通的 promise 一样,具有自动捕获同步异常并转为 rejected Promise 的能力,方便链上的错误补抓函数执行;同时避免了金字塔型代码,格式扁平化。

js 复制代码
// 同步错误自动捕获
Promise.try(() => {
  throw new Error('Sync Error')
}).catch(console.log) // 输出错误信息

async 函数

基本使用

Async/await 是 JavaScript 中处理异步操作的一种更优雅的语法,它建立在 Promise 之上,使异步代码看起来更像同步代码,可读性更高。

使用 async 关键字可以便捷创建一个异步函数。

js 复制代码
async function func() {/*...*/}

// 类似以下代码
function func(){
    return new Promise(function(){
        /*...*/
    })
}
  • 返回值会被包装成一个 Promise;
  • 非 Promise 返回值会被自动包装成 resolved Promise;

async 函数内使用关键字 await ,可让异步函数阻塞,直到 promise 完成,并将结果值返回。

js 复制代码
async function f() {
  let promise = new Promise(resolve => {
    setTimeout(() => resolve("done!"), 1000)
  });
  
  let result = await promise; // 等待直到 promise 完成
  
  console.log(result); // "done!"
}
  • 只能在 async 函数内部使用,阻塞 async 函数;
  • 不会阻塞主线程,JavaScript 引擎可以处理其他任务;
  • 使用 await 后返回结果值,不再返回一个 Promise,无需 .then 方法。

错误处理

可以使用 try/catch 捕获错误:

javascript 复制代码
async function f() {
  try {
    let response = await fetch('http://no-such-url');
    let data = await response.json();
  } catch(err) {
    console.error("请求失败:", err);
  }
}

若没有 try..catch,那么调用生成的 promise 将变为 rejected。可在函数调用后面添加 .catch 来处理这个 error:

javascript 复制代码
f().catch(alert); // 处理未捕获的错误

若不添加 .catch,则需全局监听unhandledrejection 事件,处理promise 抛出的错误:

js 复制代码
// 浏览器环境
window.addEventListener('unhandledrejection', event => {
  console.error('未处理的Promise错误:', event.reason);
  event.preventDefault(); // 阻止默认错误输出
});

其他用法

  1. 顶层 await(仅在模块中):

    现代浏览器在 modules 里允许顶层的 await

    若没有使用 modules,或者必须兼容旧版本浏览器,那么可以包装到匿名的异步函数中:

    js 复制代码
    (async () => {
      let response = await fetch('/article/promise-chaining/user.json');
      let user = await response.json();
      // ...
    })();
  2. 处理 thenable 对象

    await 允许使用 thenable 对象(兼容 promise 的对象,具有可调用的 .then 方法)

    js 复制代码
    class Thenable {
      constructor(num) {
        this.num = num;
      }
      then(resolve, reject) {
        setTimeout(() => resolve(this.num * 2), 1000);
      }
    }
    
    async function f() {
      let result = await new Thenable(1);
      console.log(result); // 2
    }
  3. 类中的 async 方法

    要声明一个 class 中的 async 方法,只需在对应方法前面加上 async 即可。

    js 复制代码
    class Waiter {
      async wait() {
        return await Promise.resolve(1);
      }
    }
    
    new Waiter().wait().then(console.log); // 1
  4. 支持 Promise 的静态方法

    js 复制代码
    // 并行处理多个 Promise
    let results = await Promise.all([
      fetch(url1),
      fetch(url2),
      fetch(url3)
    ]);
相关推荐
同志327136 分钟前
用HTML+CSS做了一个网易云音乐客户端首页
前端·css
小猪欧巴哟7 分钟前
pnpm install 安装项目依赖遇到 illegal operation on a directory, symlink 问题
前端·vue.js
独角仙梦境7 分钟前
🚀🚀🚀学习这个思路,你也能手撸自己的专属vip脚手架🚀🚀🚀
前端
CJWbiu10 分钟前
Github Action + docker 实现自动化部署
前端·自动化运维
关山11 分钟前
在TS中如何在子进程中动态实例化一个类
前端
吃瓜群众i12 分钟前
兼容IE8浏览器的8个实用知识点
前端·javascript
前端烨15 分钟前
vue3子传父——v-model辅助值传递
前端·vue3·组件传值
猫头虎32 分钟前
如何解决IDE项目启动报错 error:0308010C:digital envelope routines::unsupported 问题
javascript·ide·vue.js·typescript·node.js·编辑器·vim
Mintopia1 小时前
Three.js 在数字孪生中的应用场景教学
前端·javascript·three.js
da-peng-song1 小时前
ArcGIS arcpy代码工具——根据属性结构表创建shape图层
javascript·python·arcgis