IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    在JavaScript中从外部解决Promise:实际应用场景

    王大冶发表于 2024-08-27 17:37:46
    love 0

    image.png

    • CSS技巧与案例详解
    • vue2与vue3技巧合集
    • VueUse源码解读

    这是JavaScript中那些在现实世界中极其强大的酷炫技巧之一。

    强大的实际应用场景

    动作(A)等待另一个动作(B)

    A正在进行,但用户想做B,而A需要先发生。

    例如:社交应用,用户可以创建、保存和发布帖子。就像Medium。

    <p>
      Save status:
      <b><span id="save-status">Not saved</span></b>
    </p>
    <p>
      Publish status:
      <b><span id="publish-status">Not published</span></b>
    </p>
    <button id="save">Save</button>
    <button id="publish">Publish</button>
    

    image.png

    如果用户想在帖子保存时发布怎么办?

    解决方案:确保在发布之前帖子已保存。

    saveButton.onclick = () => {
      save();
    };
    
    publishButton.onclick = async () => {
      await publish();
    };
    
    let saveResolve;
    
    let hasSaved = false;
    
    async function save() {
      hasSaved = false;
      saveStatus.textContent = 'Saving...';
      // ✅ Resolve promise from outside
      await makeSaveRequest();
      saveResolve();
      hasSaved = true;
      saveStatus.textContent = 'Saved';
    }
    
    async function waitForSave() {
      if (!hasSaved) {
        await new Promise((resolve) => {
          saveResolve = resolve;
        });
      }
    }
    
    async function publish() {
      publishStatus.textContent = 'Waiting for save...';
      await waitForSave();
      publishStatus.textContent = 'Published';
      return;
    }
    

    当你将这个逻辑抽象成一种Deferred类时,它变得更好:

    class Deferred {
      constructor() {
        this.promise = new Promise((resolve, reject) => {
          this.reject = reject;
          this.resolve = resolve;
        });
      }
    }
    
    const deferred = new Deferred();
    
    // Resolve from outside
    deferred.resolve();
    

    重构✅:

    const deferredSave = new Deferred();
    let hasSaved = false;
    
    async function save() {
      hasSaved = false;
      saveStatus.textContent = 'Saving...';
      // 🟢 Resolve promise from outside
      await makeSaveRequest();
      saveResolve();
      hasSaved = true;
      saveStatus.textContent = 'Saved';
    }
    
    async function waitForSave() {
      if (!hasSaved) await deferredSave.promise;
    }
    
    async function publish() {
      // ...
    }
    

    它的工作方式与之前完全相同:

    Deferred更加清晰,这就是为什么我们有很多类似的NPM库:ts-deferred、deferred、promise-deferred...

    image.png

    将事件流转换为Promise

    这是我多次使用过的一个很好的设置。

    执行一个异步任务,实际上是在内部等待事件流触发:

    // data-fetcher.js
    const deferred = new Deferred();
    
    let dataDeferred;
    function startListening() {
      dataDeferred = new Deferred();
    
      eventStream.on('data', (data) => {
        dataDeferred.resolve(data);
      });
    }
    
    async function getData() {
      return await dataDeferred.promise;
    }
    
    // client.js
    const { startListening, getData } = require('./data-fetcher.js');
    startListening();
    // 🟢 Waits for event to happen once
    const data = await getData();
    

    最后的思考

    从外部解决Promise可以解锁强大的模式。

    它保持你的代码清晰和灵活,从用户操作到事件流。而像ts-deferred这样的库为我们提供了更好的处理方式。

    首发于公众号 大迁世界,欢迎关注。📝 每周一篇实用的前端文章 🛠️ 分享值得关注的开发工具 ❓ 有疑问?我来回答

    本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。



沪ICP备19023445号-2号
友情链接