Skip to content

进入 stage3 的 Promise.withResolvers 提案可以怎么用?

Promise.withResolvers 提案最近进入了 stage3,大概率最终会落地进入 ECMAScript 规范。趁着这个时机,我们可以来了解下 Promise.withResolvers 实际可以怎么用。

背景

如果我们需要在实例化 Promise 后配置它的解析和拒绝行为,我们一般从 Promise 回调范围中提取 resolvereject 函数。

发起请求

以下就是一个发起请求的例子。

js
function myRequest(config) {
  let resolve;
  let reject;
  const promise = new Promise((_resolve, _reject) => {
    // 提取 resolve 和 reject 在别处使用
    resolve = _resolve;
    reject = _reject;
  });
  request(config, (response) => {
    const buffer = [];
    response.on('data', (data) => buffer.push(data));
    response.on('end', () => resolve(buffer)); // 在这里使用 resolve
    response.on('error', (reason) => reject(reason)); // 在这里使用 reject
  });
  return promise;
}

现在大部分人都在使用 axios,可能以上例子并不十分直观。

socket

以下是一个使用 socket 的例子。

js
let resolve;
let reject;
function request(type, message) {
  if (socket) {
    const promise = new Promise((_resolve, _reject) => {
      // 提取 resolve 和 reject 在别处使用
      resolve = _resolve;
      reject = _reject;
    });
    socket.emit(type, message);
    return promise;
  }
  return Promise.reject(new Error('Socket unavailable'));
}
socket.on('response', (response) => {
  if (response.status === 200)
    resolve(response); // 在这里使用 resolve
  else reject(new Error(response)); // 在这里使用 reject
});
socket.on('error', (err) => reject(err)); // 在这里使用 reject

可取消计时器

以下是一个可取消计时器的例子。

js
function cancelableTimeout(ms) {
  let cancel;
  const promise = new Promise((resolve, reject) => {
    const timeoutId = setTimeout(resolve, ms); // 在这里使用 resolve
    cancel = () => {
      clearTimeout(timeoutId);
      reject(new Error('The timeout was canceled.')); // 在这里使用 reject
    };
  });
  return { cancel, promise };
}

更多

你可能还了解过一些相关概念,比如 deferdeferred。它们的实现都是类似的,你可以在 react 代码库vue 代码库vite 代码库axios 代码库 见到它们。

解决方案

Promise.withResolvers 提案试图为 Promise 添加一个静态方法 withResolvers,返回一个 Promise 实例和相关的 resolvereject

js
const { promise, reject, resolve } = Promise.withResolvers();

借助这个提案,上面三个例子可以进一步简化。

发起请求

js
function myRequest(config) {
  let resolve; 
  let reject; 
  const promise = new Promise((_resolve, _reject) => {

    resolve = _resolve; 
    reject = _reject; 
  }); 
  const { promise, resolve, reject } = Promise.withResolvers(); 
  request(config, (response) => {
    const buffer = [];
    response.on('data', (data) => buffer.push(data));
    response.on('end', () => resolve(buffer));
    response.on('error', (reason) => reject(reason));
  });
  return promise;
}

socket

js
let resolve; 
let reject; 
const { promise, resolve, reject } = Promise.withResolvers(); 
function request(type, message) {
  if (socket) {
    const promise = new Promise((_resolve, _reject) => {

      resolve = _resolve; 
      reject = _reject; 
    }); 
    socket.emit(type, message);
    return promise;
  }
  return Promise.reject(new Error('Socket unavailable')); 
  return reject(new Error('Socket unavailable')); 
}
socket.on('response', (response) => {
  if (response.status === 200) resolve(response);
  else reject(new Error(response));
});
socket.on('error', (err) => reject(err));

可取消计时器

js
function cancelableTimeout(ms) {
  const { promise, resolve, reject } = Promise.withResolvers(); 
  let cancel; 
  const promise = new Promise((resolve, reject) => { 
    const timeoutId = setTimeout(resolve, ms);
    cancel = () => { 
    const cancel = () => { 
      clearTimeout(timeoutId);
      reject(new Error('The timeout was canceled.'));
    };
  }); 
  return { promise, cancel };
}

小结

Promise.withResolvers 能够有效地简化从 Promise 回调范围中提取 resolvereject 的场景。目前还比较新,需要通过 Polyfill 来使用。

提案链接

Released under the MIT License.

布局切换

调整 VitePress 的布局样式,以适配不同的阅读习惯和屏幕环境。

全部展开
使侧边栏和内容区域占据整个屏幕的全部宽度。
全部展开,但侧边栏宽度可调
侧边栏宽度可调,但内容区域宽度不变,调整后的侧边栏将可以占据整个屏幕的最大宽度。
全部展开,且侧边栏和内容区域宽度均可调
侧边栏宽度可调,但内容区域宽度不变,调整后的侧边栏将可以占据整个屏幕的最大宽度。
原始宽度
原始的 VitePress 默认布局宽度

页面最大宽度

调整 VitePress 布局中页面的宽度,以适配不同的阅读习惯和屏幕环境。

调整页面最大宽度
一个可调整的滑块,用于选择和自定义页面最大宽度。

内容最大宽度

调整 VitePress 布局中内容区域的宽度,以适配不同的阅读习惯和屏幕环境。

调整内容最大宽度
一个可调整的滑块,用于选择和自定义内容最大宽度。

聚光灯

支持在正文中高亮当前鼠标悬停的行和元素,以优化阅读和专注困难的用户的阅读体验。

ON开启
开启聚光灯。
OFF关闭
关闭聚光灯。