Vue3,用组合编写更好的代码:Async Without Await 模式

更新日期: 2022-07-02阅读: 919标签: Vue3作者: 前端小智

如果能让异步代码正确工作,它可以大大简化我们代码。但是,处理这种额外的复杂性,特别是与可合一起,可能会令人困惑。这篇文章介绍了无等待的异步模式。这是一种在组合中编写异步代码的方法,而不像通常那样令人头疼。

无等待的异步

用组合api编写异步行为有时会很麻烦。所有的异步代码必须在任何反应式代码之后的设置函数的末端。如果你不这样做,它可能会干扰你的反应性。

当setup函数运行到一个await语句时,它将返回。一旦它返回,该组件就会被挂载,并且应用程序会像往常一样继续执行。任何在await之后定义的响应式,无论是 computed、watcher,还是其他什么,都还没有被初始化。

这意味着,一个在await之后定义的计算属性一开始不会被模板使用。相反,只有在异步代码完成,setup 函数完成执行后,它才会存在。

然而,有一种方法可以编写异步组件,可以在任何地方使用,而不需要这些麻烦。

const count = ref(0);
// 这种异步数据获取不会干扰我们的响应式
const { state } = useAsyncState(fetchData());
const doubleCount = computed(() => count * 2);

实现没有等待的异步模式

为了实现这一模式,我们将同步地挂起所有的响应式值。然后,每当异步代码完成后,这些值将被异步更新。

首先,我们需要把我们的状态准备好并返回。我们将用一个null的值来初始化,因为我们还不知道这个值是什么。

export default useMyAsyncComposable(promise) {
  const state = ref(null);
  return state;
}

第二,我们创建一个方法,等待我们的 promise ,然后将结果设置为 state:

const execute = async () => {
  state.value = await promise;
}

每当这个promise 返回时,它就会主动更新我们的state。

现在我们只需要把这个方法添加到组合中。

export default useMyAsyncComposable(promise) {
  const state = ref(null);

  // Add in the execute method...
  const execute = async () => {
    state.value = await promise;
  }

  // ...and execute it!
  execute();

  return state;
}

我们在从useMyAsyncComposable方法返回之前调用了execute函数。然而,我们并没有使用await关键字。

当我们停止并等待execute方法中的 promise 时,执行流立即返回到useMyAsyncComposable函数。然后它继续执行execute()语句并从可组合对象返回。

export default useMyAsyncComposable(promise) {
  const state = ref(null);

  const execute = async () => {
    // 2. 等待 promise 执行完成
    state.value = await promise

    // 5. 一段时间后...
    // Promise 执行完,state 更新
    // execute 执行完成
  }

  // 1. 执行 `execute` 方法
  execute();
  // 3.  await 将控制权返回到这一点上。

  // 4. 返回 state 并继续执行 "setup" 方法
  return state;
}

promise在后台执行,因为我们没有等待它,所以它不会在setup函数中中断流。我们可以将此可组合放置在任何地方,而不影响响应性。

让我们看看 vueUse 中一些组合是如何实现这种模式的。

useAsyncState

useAsyncState 可以让我们在任何地方执行任何异步方法,并获得响应性的更新结果。

const { state, isLoading } = useAsyncState(fetchData());

在查看源代码时,可以看到它实现了这种精确的模式,但具有更多的特性,并能更好地处理边界情况。

下面是 useAsyncState 的一个简化版:

export function useAsyncState(promise, initialState) {
  const state = ref(initialState);
  const isReady = ref(false);
  const isLoading = ref(false);
  const error = ref(undefined);

  async function execute() {
    error.value = undefined;
    isReady.value = false;
    isLoading.value = true;

    try {
      const data = await promise;
      state.value = data;
      isReady.value = true;
    }
    catch (e) {
      error.value = e;
    }

    isLoading.value = false;
  }

  execute();

  return {
    state,
    isReady,
    isLoading,
    error,
  };
}

这个可组合的系统还返回isReady,告诉我们数据何时被取走。我们还得到了isLoading和error,以跟踪我们的加载和错误状态。

现在来看看另一个可组合,我认为它有一个迷人的实现方式。

useAsyncQueue

如果传给useAsyncQueue一个 promise 函数数组,它会按顺序执行每个函数。所以,在开始下一个任务之前,会等待前一个任务的完成。为了使用更灵活,它上一个任务的结果作为输入传给下一个任务。

const { result } = useAsyncQueue([getFirstPromise, getSecondPromise]);

下面是一个官网的例子:

const getFirstPromise = () => {
  // Create our first promise
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(1000);
    }, 10);
  });
};

const getSecondPromise = (result) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(1000 + result);
    }, 20);
  });
};

const { activeIndex, result } = useAsyncQueue([
  getFirstPromise,
  getSecondPromise
]);

即使它在异步执行代码,我们也不需要使用await。即使在内部,可组合的程序也不使用await。相反,我们在 "后台"执行这些 promise,并让结果响应式更新。

让我们看看这个组合是如何工作的。

// 初始一些默认值
const initialResult = Array.from(new Array(tasks.length), () => ({
  state: promiseState.pending,
  data: null,
});

// 将默认值变成响应式
const result = reactive(initialResult);

// 声明一个响应式的下标
const activeIndex = ref(-1);

主要的功能是由一个reduce来支持的,它逐个处理每个功能

tasks.reduce((prev, curr) => {
  return prev.then((prevRes) => {
    if (result[activeIndex.value]?.state === promiseState.rejected && interrupt) {
      onFinished();
      return;
    }

    return curr(prevRes).then((currentRes) => {
      updateResult(promiseState.fulfilled, currentRes);
      activeIndex.value === tasks.length - 1 && onFinished();
      return currentRes;
    })
  }).catch((e) => {
    updateResult(promiseState.rejected, e);
    onError();
    return e;
  })
}, Promise.resolve());

Reduce 方法有点复杂,我们拆解一下,一个个看:

tasks.reduce((prev, curr) => {
  // ...
}, Promise.resolve());

然后,开始处理每个任务。通过在前一个promise基础上链接一个.then来完成这个任务。如果promise 被拒绝,就提前中止并返回。

if (result[activeIndex.value]?.state === promiseState.rejected && interrupt) {
  onFinished();
  return;
}

如果不提前终止,则执行下一个任务,并传递上一个 promise 的结果。我们还调用updateResult方法,将其添加到该组合返回的 result 数组中

return curr(prevRes).then((currentRes) => {
  updateResult(promiseState.fulfilled, currentRes);
  activeIndex.value === tasks.length - 1 && onFinished();
  return currentRes;
});

正如你所看到的,该可组合实现了Async Without Await模式,但该模式只是整个可组合的几行。所以它不需要很多额外的工作,只要记住把它放在适当的位置

总结

如果我们使用Async Without Await模式,我们可以更容易地使用异步组合。这种模式可以让我们把异步代码放在我们想放的地方,而不用担心破坏响应应性。

来源:https://segmentfault.com/a/1190000042060845

链接: https://www.fly63.com/article/detial/11839

vue3.x 新特性 - CompositionAPI

安装 vue-cli3,在使用任何 @vue/composition-api 提供的能力前,必须先通过 Vue.use() 进行安装,安装插件后,您就可以使用新的 Composition API 来开发组件了。

Vue3数据响应系统

Vue3 就是基于 Proxy 对其数据响应系统进行了重写,现在这部分可以作为独立的模块配合其他框架使用。数据响应可分为三个阶段: 初始化阶段 --> 依赖收集阶段 --> 数据响应阶段

快速进阶Vue3.0

在2019.10.5日发布了Vue3.0预览版源码,但是预计最早需要等到 2020 年第一季度才有可能发布 3.0 正式版。新版Vue 3.0计划并已实现的主要架构改进和新功能:

Vue 3 对 Web 应用性能的改进

有关即将发布的 Vue.js 的第 3 个主要版本的信息越来越多。通过下面的讨论,虽然还不能完全确定其所有内容,但是我们可以放心地认为,它将是对当前版本(已经非常出色)的巨大改进。 Vue 团队在改进框架 API 方面做得非常出色

Vue3 中令人兴奋的新功能

用新的 Vue 3 编写的程序效果会很好,但性能并不是最重要的部分。对开发人员而言,最重要的是新版本将会怎样影响我们编写代码的方式。如你所料,Vue 3 带来了许多令人兴奋的新功能。值得庆幸的是

200 行从零实现 vue3

emmm 用半天时间捋顺了 vue3 的源码,再用半天时间写了个 mini 版……我觉得我也是没谁了,vue3 的源码未来一定会烂大街的,我们越早的去复现它,就……emm可以越早的装逼hhh

从 Proxy 到 Vue 源码,深入理解 Vue 3.0 响应系统

10 月 5 日,尤雨溪在 GitHub 开放了 Vue 3.0 处于 pre-alpha 状态的源码,这次 Vue 3.0 Updates 版本的更新,将带来五项重大改进:速度体积、可维护性、面向原生、易用性

Vue 的数据响应式(Vue2 及 Vue3)

从一开始使用 Vue 时,对于之前的 jq 开发而言,一个很大的区别就是基本不用手动操作 dom,data 中声明的数据状态改变后会自动重新渲染相关的 dom。换句话说就是 Vue 自己知道哪个数据状态发生了变化及哪里有用到这个数据需要随之修改。

在Vue2与Vue3中构建相同的组件

Vue 开发团队终于在今天发布了 3.0-beta.1 版本,也就是测试版。通常来说,从测试版到正式版,只会修复 bug,不会引入新功能,或者删改老功能。所以,如果你对新版本非常感兴趣,或者有新项目即将上马,不妨尝试一下新版本

Vue3中的Vue Router初探

对于大多数单页应用程序而言,管理路由是一项必不可少的功能。随着新版本的Vue Router处于Alpha阶段,我们已经可以开始查看下一个版本的Vue中它是如何工作的。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!