Promise 一个基于协程下的任务队列状态管理任务包 解决复杂的异步转同步问题

前言

一直都想写关于Promise的东西,Promise解决的问题特别多,而普通前端就把这东西结合ajax来做一个await request() ,如果仅仅作为这样一种东西使用那就太可惜了。

Promise 就是一个任务包的状态控制对象,new Promise后,内部会传入一个函数,这个函数里面有一个执行过程,这个过程往往是异步的,但不管里面的逻辑如何,最终只要调用Promise给的resolve(),就代表这个任务包被处理完毕了,所以这个时间是不确定的,之后就能做Promise.then的事情了。

这在Node.js开发的协程服务简直完美,可以这样理解,原来基于线程的Java会为每个请求建立一个线程,线程的调度是CPU级别的,里面的变量也不是共享的,处理起来比较麻烦,而且每个线程都是独立的,只要线程处于等待状态,里面的拷贝的变量都会一直存在,对内存,对cpu都有消耗。

之后node.js协程调度来了,所有的请求都只是一个协程,每个请求被作为一个队列堆起来,所有的系统上下文都在一个线程里面,无需拷贝,调度过程也是yield语句直接切换,cpu和内存消耗都大大降低,也没有线程的概念,这对于高并发长等待的请求来说,简直完美,就可以理解为java能开300个线程,而换成了Node.js可以开上万个连接支持websocket,因为所有建立的websocket都在一个进程里,上下文并没有单开线程,也没有线程间的调度,最方便的是,引入了Pomise的话,用户根本不用区分那个协程的请求,Promise本身会将这些变量保存起来

比如说,请求1发过来的req,如果作为闭包函数塞入Promise((r,rj) => {req,res}),那么等这个请求完全处理完成后,再调用res.json(xxx) 时,这里的res自然就会调用本次请求的协程上下文,返回给请求的结果,而无需你再来写什么调度逻辑,去找到这个连接的fd,然后再实例化这个fd,然后再发送出去了,方便地不能再方便了。

如果你看看其他语言,例如Go,python,或者hyperf(php协程框架),就会知道Promise的简便性是无法比拟的,只要你用了一次,就会被这种简单紧紧吸引。

它是队列的任务包

前端同学应该是没听说过队列,但是大前端同学,例如搞安卓的或者IOS的肯定听过,在安卓开发种,所有的UI操作都需要给主进程处理,这里的new Runnable() 就很像Promise

安卓里面的线程子类

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.textView);
        handler = new Handler(Looper.getMainLooper());

        // 启动一个子线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 模拟一些后台工作
                try {
                    Thread.sleep(2000); // 模拟耗时操作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                // 更新UI,必须在主线程中进行
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("更新后的文本");
                    }
                });
            }
        }).start();
    }
}

Python 协程中的Future

import asyncio

def async_task(future, success=True):
    async def task():
        await asyncio.sleep(2)
        if success:
            future.set_result("Task completed successfully")
        else:
            future.set_exception(ValueError("Something went wrong"))
    return task()

def success_callback(result):
    print(f"Success: {result}")

def error_callback(error):
    print(f"Error: {error}")

async def main():
    future = asyncio.Future()
    
    # 启动异步任务
    asyncio.create_task(async_task(future))
    
    # 注册成功和错误回调
    future.add_done_callback(lambda f: success_callback(f.result()) if not f.exception() else error_callback(f.exception()))
    
    # 等待 Future 完成
    await future

# 运行事件循环
asyncio.run(main())

Promise 的异步转同步操作

function updateDomElement(element, newValue) {
  return new Promise((resolve, reject) => {
    // 假设这里是一个异步的DOM更新操作
    element.textContent = newValue;

    // 模拟DOM更新完毕,触发一个自定义事件
    const event = new Event('domUpdated');
    setTimeout(() => {
      element.dispatchEvent(event);
    }, 1000); // 1秒后触发更新完成事件

    // 监听自定义事件,表示DOM更新完毕
    element.addEventListener('domUpdated', function onDomUpdated() {
      element.removeEventListener('domUpdated', onDomUpdated);
      resolve(true); // 触发Promise的resolve
    });

    // 如果有可能的错误情况,也可以调用reject(error)
  });
}

// 使用示例
async function performOperation() {
  const element = document.getElementById('myElement');
  
  // 更新DOM元素,并等待更新完成
  await updateDomElement(element, "New Content");

  // DOM更新完成后继续操作
  console.log("DOM updated successfully. Now performing next operations...");
  // 继续后续操作
}

performOperation();

创建一个Promise,直到有人调用了这个Promise.resolve()函数

只要你理解了上面任务包的概念之后,并且你知道只要有人调用了Promise.resolve()这个函数后,这个任务包就处理成功了,那么只要你创建了它,就相当于塞到了事件循环队列里去了。

await就是一个生产者,同时还把它下面的代码都自动封装成了回调函数,之后的就没有自己的故事了。

async 相当于一个消费者,负责等待任务逻辑调用这个Promise.resolve()函数,一旦有逻辑调用了Promise.resolve函数,就意味着这个Promise任务被处理完毕了,就可以开始它的后续回调了。

Promise都有哪些用途?

  1. 你试试用promise将websocket封装为一个await wsrequest(),这样能让你像调用http一样调用websocket,非常方便,怎么搞?

  2. https://blog.csdn.net/wangsenling/article/details/130224796icon-default.png?t=N7T8https://blog.csdn.net/wangsenling/article/details/130224796

  3. 插件与网页的异步通信,上面已有演示,通过事件的方式,来回倒腾,实现同步请求

  4. 谷歌插件inject注入脚本与content script基于Promise+async/await 同步通信实现过程_chrome plugin inject-CSDN博客文章浏览阅读1.1k次。因为webpage和contentscript是两个隔离环境,在webpage(普通网页)中有CSP安全机制,而在macm1环境,MV3版本下无法修改response.header这个bug半年前反馈给谷歌,后续也没见结果,所以,想在webpage网页中直接请求远程url是走不通的,只有借助contentscript来协助请求数据,但是这里牵涉到两个步骤,能否实现异步转同步方式来处理这个过程?_chrome plugin injecthttps://blog.csdn.net/wangsenling/article/details/129918148

  5. 网页UI的动画或者状态变化的后续操作,demo省略

  6. Electron中各种复杂调度下的异步转同步操作

总之把Promise运用在异步转同步的构建上,才能发挥出Promise存在的意义,可以理解为一切异步操作都可以用Promise来封装,实现完美的调度逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

森叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值