javascript - React.js 告诉你取消 promise 。官方 promise 不能取消。我应该怎么做?

标签 javascript reactjs es6-promise cancellation

为了防止对未安装的 React 组件进行幻像更新,React 会告诉您 cancel any pending promises卸载时在组件上(例如获取附加数据的 promise )。使用 Bluebird Promise 很容易做到这一点,它有一个 .cancel()导致 .then() 的方法和 .catch()处理程序从不响应。

但是,ES6 Promises 不支持取消。另外,ES7 的 asyncawait仅使用原生 Promises,不支持任何插入式替换(例如 Bluebird)。这意味着如果你想在 React 中取消 Promise,就像他们告诉你的那样,你必须使用 .then().catch()并且还必须在本地 Promise 方法上放置一个中间人,例如 fetch()以便可以取消。

这真的是 React 所期望的吗?

最佳答案

仅供引用。
使用 CPromise 包,您可以取消您的 promise 链,包括嵌套的。它支持 AbortController 和生成器作为 ECMA 异步函数的替代品。目前该项目处于测试阶段。
生成器使用 Live Demo :

import CPromise from "c-promise2";

const chain = CPromise.resolve()
  .then(function* () {
    const value1 = yield new CPromise((resolve, reject, { onCancel }) => {
      const timer = setTimeout(resolve, 1000, 3);
      onCancel(() => {
        console.log("timer cleared");
        clearTimeout(timer);
      });
    });
    // Run promises in parallel using CPromise.all (shortcut syntax)
    const [value2, value3] = yield [
      CPromise.delay(1000, 4),
      CPromise.delay(1000, 5)
    ];
    return value1 + value2 + value3;
  })
  .then(
    (value) => {
      console.log(`Done: ${value}`); // Done: 12 (without calling cancel)
    },
    (err) => {
      console.log(`Failed: ${err}`); // Failed: CanceledError: canceled
    }
  );

setTimeout(() => chain.cancel(), 100);
输出:
timer cleared 
Failed: CanceledError: canceled 
那里的所有阶段都是完全可取消/可中止的。
这是一个将它与 React Live Demo 一起使用的示例
export class TestComponent extends React.Component {
  state = {};

  async componentDidMount() {
    console.log("mounted");
    this.controller = new CPromise.AbortController();
    try {
      const json = await this.myAsyncTask(
        "https://run.mocky.io/v3/7b038025-fc5f-4564-90eb-4373f0721822?mocky-delay=2s"
      );
      console.log("json:", json);
      await this.myAsyncTaskWithDelay(1000, 123); // just another async task
      this.setState({ text: JSON.stringify(json) });
    } catch (err) {
      if (CPromise.isCanceledError(err)) {
        console.log("tasks terminated");
      }
    }
  }

  myAsyncTask(url) {
    return CPromise.from(function* () {
      const response = yield cpFetch(url); // cancellable request
      return yield response.json();
    }).listen(this.controller.signal);
  }

  myAsyncTaskWithDelay(ms, value) {
    return new CPromise((resolve, reject, { onCancel }) => {
      const timer = setTimeout(resolve, ms, value);
      onCancel(() => {
        console.log("timeout cleared");
        clearTimeout(timer);
      });
    }).listen(this.controller.signal);
  }

  render() {
    return (
      <div>
        AsyncComponent: <span>{this.state.text || "fetching..."}</span>
      </div>
    );
  }
  componentWillUnmount() {
    console.log("unmounted");
    this.controller.abort(); // kill all pending tasks
  }
}
Using Hooks and cancel method
import React, { useEffect, useState } from "react";
import CPromise from "c-promise2";
import cpFetch from "cp-fetch";

export function TestComponent(props) {
  const [text, setText] = useState("fetching...");

  useEffect(() => {
    console.log("mount");
    const promise = cpFetch(props.url)
      .then(function* (response) {
        const json = yield response.json();
        setText(`Delay for 2000ms...`);
        yield CPromise.delay(2000);
        setText(`Success: ${JSON.stringify(json)}`);
      })
      .canceled()
      .catch((err) => {
        setText(`Failed: ${err}`);
      });

    return () => {
      console.log("unmount");
      promise.cancel();
    };
  }, [props.url]);

  return <p>{text}</p>;
}

关于javascript - React.js 告诉你取消 promise 。官方 promise 不能取消。我应该怎么做?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59568434/

相关文章:

javascript - 从重复对象数组中返回最新值

c# - 为什么我的 ReactiveUserControl 或 ReactUI 应用程序无法使用 Selenium 自动测试和 WinAppDriver(C# 测试解决方案)

javascript - 添加实现到 Promise.resolve

javascript - 我对 new Promise((resolve, reject) => {[loop]}) 阻塞而 Promise.resolve().then([loop]) 不是阻塞感到困惑

javascript - 如何在 POST 请求中以逗号分隔的列表中的 "escape"逗号?

javascript - requireJs - 它真的有助于性能吗?

JavaScript 在不使用 CSS 的情况下移动过渡

javascript - 检查 Web 应用程序是否安装了 React、Angular 或 Vue

ruby-on-rails - React with Rails 5.1 将数据库对象调用到 React 组件中

Javascript Promises 显式函数与内联函数