万字复盘 Handler 中各式 Message 的使用和原理(2)

简介: 万字复盘 Handler 中各式 Message 的使用和原理(2)

异步执行 Message

1832b220aa754cd18c504acc7686a560.png

Handler 发送的 Message 都是同步的,意味着大家都按照 when 的先后进行排序,谁先到谁执行。


如果遇到优先级高的 Message 可以通过 FrontQueue 发送插队 Message即可。但如果是希望同步的队列停滞只执行指定 Message 的话,即 Message 异步执行,现有的 API 是不够的。


事实上 Android 提供了同步屏障的机制来实现这一需求,不过主要面向的是系统 App 或 系统,App 可以通过反射来使用。

通过异步 Handler 实现

除了一般使用的 Handler 构造函数以外,Handler 还提供了创建发送异步 Message 的专用构造函数。通过该 Handler 发送的 Message 或 Runnable 都是异步的。我们将其称为异步 Handler

// Handler.java
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    @NonNull
    public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
        if (looper == null) throw new NullPointerException("looper must not be null");
        if (callback == null) throw new NullPointerException("callback must not be null");
        return new Handler(looper, callback, true);
    }

我们启动一个 HandlerThread 来测试一下同步屏障的使用:分别构建一个普通 Handler异步 Handler

    private fun startBarrierThread() {
        val handlerThread = HandlerThread("Test barrier thread")
        handlerThread.start()
        normalHandler = Handler(handlerThread.looper) { msg ->
            Log.d(...)
            true
        }
        barrierHandler = Handler.createAsync(handlerThread.looper) { msg ->
            Log.d(...)
            true
        }
    }

启动 HandlerThread 并向两个 Handler 各发送一个 Message。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        startBarrierThread()
        testNormalMessage()
        testSyncBarrierByHandler()
    }
    private fun testNormalMessage() {
        sendMessageRightNow(normalHandler, 1)
    }
    private fun testSyncBarrierByHandler() {
        sendMessageRightNow(barrierHandler, 2)
    }

是异步 Handler 的 Message 先执行吗?非也,因为我们还没有通知 MessageQueue 建立同步屏障!

09-24 23:02:19.032 28113 28113 D MainActivity: onCreate()
09-24 23:02:19.150 28113 28141 D MainActivity: Normal handler message occurred & what:1
09-24 23:02:19.150 28113 28141 D MainActivity: Barrier handler message occurred & what:2

除了发送异步Handler 发送异步 Message 以外,需要通过反射事先建立起同步屏障。

注意:建立同步屏障必须早于需要屏蔽的同步 Message,否则无效,后面的原理会提及。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        startBarrierThread()
        // 建立一个同步屏障
        postSyncBarrier(barrierHandler.looper)
        testNormalMessage()
        testSyncBarrierByHandler()
    }
    private fun postSyncBarrier(looper: Looper) {
        Log.d(...)
        val method: Method = MessageQueue::class.java.getDeclaredMethod("postSyncBarrier")
        barrierToken = method.invoke(looper.queue) as Int
    }

这样子便可以看到,异步 Message 执行了,而且同步 Message 永远得不到执行。

09-24 23:11:36.176 28600 28600 D MainActivity: onCreate()
09-24 23:11:36.296 28600 28600 D MainActivity: Add sync barrier
09-24 23:11:36.300 28600 28629 D MainActivity: Barrier handler message occurred & what:2

原因在于建立的同步屏障尚未移除,永远只处理队列里的异步 Message。想要让同步 Message 恢复执行的话 remove 同步屏障即可,同样也需要反射!

我们在异步 Handler 执行结束后移除同步屏障。

    private fun startBarrierThread() {
        ...
        barrierHandler = Handler.createAsync(handlerThread.looper) { msg ->
            Log.d(...)
            // 移除同步屏障
            removeSyncBarrier(barrierHandler.looper)
            true
        }
    }
    fun removeSyncBarrier(looper: Looper) {
        Log.d(...)
        val method = MessageQueue::class.java
            .getDeclaredMethod("removeSyncBarrier", Int::class.javaPrimitiveType)
        method.invoke(looper.queue, barrierToken)
    }

可以看到同步 Message 恢复了。

09-24 23:10:31.533 28539 28539 D MainActivity: onCreate()
09-24 23:10:31.652 28539 28568 D MainActivity: Barrier handler message occurred & what:2
09-24 23:10:31.652 28539 28568 D MainActivity: Remove sync barrier
09-24 23:10:31.653 28539 28568 D MainActivity: Normal handler message occurred & what:1

通过异步 Message 实现

没有专用的异步 Handler 的时候,可以向普通 Handler 发送一个 isAsync 属性为 true 的 message,效果和异步 Handler 是一样的。当然这种方式仍旧需要建立同步屏障。

在原有的发送 Message 的函数里加入 isAsync 的重载参数。

    private fun sendMessageRightNow(handler: Handler, what: Int, isAsync: Boolean = false) {
        Message.obtain().let {
            it.what = what
            it.isAsynchronous = isAsync
            handler.sendMessage(it)
        }
    }

向普通 Handler 发送异步 Message。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        testNormalMessage()
        // 改用 Message 方式发送异步 Message
        testSyncBarrierByMessage()
    }
    private fun testSyncBarrierByMessage() {
        sendMessageRightNow(normalHandler, 2, true)
    }

同样记得在异步 Message 收到后移除同步屏障。

    private fun startBarrierThread() {
        ...
        normalHandler = Handler(handlerThread.looper) { msg ->
            Log.d(...)
            if (2 == msg.what) removeSyncBarrier(barrierHandler.looper)
            true
        }
    }

结果和异步 Handler 的方式一致。

09-24 23:58:05.801 29040 29040 D MainActivity: onCreate()
09-24 23:58:05.923 29040 29040 D MainActivity: Add sync barrier
09-24 23:58:05.923 29040 29070 D MainActivity: Normal handler message occurred & what:2
09-24 23:58:05.924 29040 29070 D MainActivity: Remove sync barrier
09-24 23:58:05.924 29040 29070 D MainActivity: Normal handler message occurred & what:1

原理

先来看一下同步屏障是怎么建立的。

// MessageQueue.java
  // 默认是调用的时刻开始建立屏障
  public int postSyncBarrier() {
        return postSyncBarrier(SystemClock.uptimeMillis());
    }
    // 同步屏障支持指定开始的时刻
  // 默认是调用的时刻,而 0 表示?
  private int postSyncBarrier(long when) {
        synchronized (this) {
            // 同步屏障可以建立多个,用计数的 Token 变量识别
            final int token = mNextBarrierToken++;
            // 获取一个屏障 Message
            // 其 target 属性为空
            // 指定 when 属性为屏障的开始时刻
            final Message msg = Message.obtain();
            msg.markInUse();
            msg.when = when;
            // 将 Token 存入屏障 Message
            // 用以识别对应的同步屏障
            msg.arg1 = token;
            // 按照 when 的先后
            // 找到屏障 Message 插入队列的适当位置
            // 所以,如果同步屏障的建立调用得晚
            // 那么在它之前的 Message 无法阻拦
            Message prev = null;
            Message p = mMessages;
            if (when != 0) {
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
            }
            // 将屏障 Message 插入
            if (prev != null) {
                msg.next = p;
                prev.next = msg;
            } else {
                // 如果队列尚无 Message
                // 或队首的 Message 时刻
                // 都比屏障 Message 要晚的话
                // 将屏障 Message 插入队首
                msg.next = p;
                mMessages = msg;
            }
            // 返回上面的 Token 给调用端
            // 主要用于移除对应的屏障
            return token;
        }
    }

再来看下异步 Message 如何执行。

// MessageQueue.java
  Message next() {
        ...
        for (;;) {
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                // 队首是屏障 Message 的话
                // 遍历找到下一个异步 Message
                if (msg != null && msg.target == null) {
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                // 没有建立同步屏障且队里有 Message
                // 或者
                // 建立了同步屏障下且找到了异步 Message
                if (msg != null) {
                    // 如果当前时间尚早于目标执行时刻
                    if (now < msg.when) {
                        // 更新下次循环应当休眠的超时时间
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        mBlocked = false;
                        // Message 找到了并出队
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        // Message 返回
                        msg.next = null;
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // 队里尚无 Message
                    // 或建立了同步屏障,但尚无异步 Message
                    // 无限休眠
                    nextPollTimeoutMillis = -1;
                }
                ...
            }
            ...
            pendingIdleHandlerCount = 0;
            nextPollTimeoutMillis = 0;
        }
    }

最后看一下同步屏障如何移除。

// MessageQueue.java
  // 需要传入 add 时返回的 Token
  public void removeSyncBarrier(int token) {
        synchronized (this) {
            Message prev = null;
            Message p = mMessages;
            // 遍历队列直到找到 token 吻合的屏障 Message
            while (p != null && (p.target != null || p.arg1 != token)) {
                prev = p;
                p = p.next;
            }
            // 如果没找到会抛出异常
            if (p == null) {
                throw new IllegalStateException("The specified message queue synchronization "
                        + " barrier token has not been posted or has already been removed.");
            }
            final boolean needWake;
            // 将屏障 Message 移除
            // 如果屏障 Message 不在队首的话
            // 无需唤醒
            if (prev != null) {
                prev.next = p.next;
                needWake = false;
            } else {
                // 屏障 Message 在队首
                // 且新的队首存在且不是另一个屏障的话
                // 需要立即唤醒
                mMessages = p.next;
                needWake = mMessages == null || mMessages.target != null;
            }
            p.recycleUnchecked();
            // 唤醒以立即处理后面的 Message
            if (needWake && !mQuitting) {
                nativeWake(mPtr);
            }
        }
    }

对原理进行简单的总结:


同步屏障的建立:按照调用的时刻 when 在合适的位置放入一个屏障 Message(target 属性为 null)来实现,同时得到标识屏障的计数 token 存入屏障 Message

读取队列的时候发现存在屏障 Message 的话,会遍历队列并返回最早执行的异步 Message

同步屏障的移除:按照 token 去队列里找到匹配的屏障 Message 进行出队操作,如果出队后队首存在 Message 且非另一个同步屏障的话,立即唤醒 looper 线程

结论和应用

结论:


可以通过异步 Handler,也可以通过异步 Message 两种方式向 MessageQueue 添加异步 Message

但都需要事先建立同步屏障,屏障的建立时间必须在阻拦的 Message 发出之前

可以建立多个同步屏障,将按照指定的时刻排队,通过计数 Token 进行识别

同步屏障使用完之后记得移除,否则后续的 Message 永远阻塞

和插队执行 Message 的区别:


    插队 Message 只能确保先执行,完了后续的 Message 还得执行

异步 Message 则不同,同步屏障一旦建立将保持休眠,直到异步 Message 抵达。只有同步屏障被撤销,后续 Message 才可恢复执行

应用:


AOSP 系统中使用异步 Message 最典型的地方要属屏幕刷新,刷新的 Message 不希望被主线程的 Message 队列阻塞,所以在发送刷新 Message 之前都会建立一个同步屏障,确保刷新任务优先执行。

// ViewRootImpl.java
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
  final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }

屏障建立之后发送异步 Message。

// Choreographer.java
  private void postCallbackDelayedInternal(...) {
        synchronized (mLock) {
            ...
            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }

IdleHandler ”Message“

1832b220aa754cd18c504acc7686a560.png

MessageQueue 提供的 IdleHandler 可以让队列在空闲的时候回调(queueIdle())指定的逻辑,它本质上不是 Message 类型,但它在 MessageQueue 里调度的时候类似于 Message 的逻辑,姑且将它也理解成一种特殊的 ”Message“。


使用上很简单,调用 MessageQueue 的 addIdleHandler() 添加实现即可,执行完之后无需再度执行的话需要调用 removeIdleHandler() 移除,或在回调里返回 false。

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        testIdleHandler()
    }
    private fun testIdleHandler() {
        Log.d("MainActivity","testIdleHandler() start")
        mainHandler.looper.queue.addIdleHandler {
            Log.d("MainActivity", "testIdleHandler() queueIdle callback")
            false
        }
        Log.d("MainActivity","testIdleHandler() end ")
    }

可以看到 addIdleHandler 调用之后并没有立即执行,而是过了几百 ms,queueIdle() 才得到了执行。

09-23 22:56:46.130  7732  7732 D MainActivity: onCreate()
09-23 22:56:46.281  7732  7732 D MainActivity: testIdleHandler() start
09-23 22:56:46.281  7732  7732 D MainActivity: testIdleHandler() end
09-23 22:56:46.598  7732  7732 D MainActivity: testIdleHandler() queueIdle callback

如果在 addIdleHandler 调用之后接着发送一串非延时 Message,queueIdle() 是先执行还是后执行呢?

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        testIdleHandler()
        testSendMessages()
    }

结果显示一堆 Message 执行完了之后,仍旧过了几百 ms,queueIdle() 才得到了执行。

09-23 23:07:50.639  7926  7926 D MainActivity: onCreate()
09-23 23:07:50.856  7926  7926 D MainActivity: testIdleHandler() start
09-23 23:07:50.856  7926  7926 D MainActivity: testIdleHandler() end
09-23 23:07:50.856  7926  7926 D MainActivity: startSendMessage() start
09-23 23:07:50.857  7926  7926 D MainActivity: startSendMessage() end
09-23 23:07:50.914  7926  7926 D MainActivity: Main thread message occurred & what:1
...
09-23 23:07:50.916  7926  7926 D MainActivity: Main thread message occurred & what:10
09-23 23:07:51.132  7926  7926 D MainActivity: testIdleHandler() queueIdle callback

上述结果也可以理解,MessageQueue 里仍有一堆 Message 等待处理,并非空闲状态。所以需要执行完之后才有机会回调 queueIdle() 。

那如果发送的是延时 Message 呢?

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    testIdleHandler()
    testSendDelayedMessages()
}

因为发送的是延时 Message,MessageQueue 暂时是空闲的,会先将 IdleHandler 取出来处理。

09-23 23:21:36.135  8161  8161 D MainActivity: onCreate()
09-23 23:21:36.339  8161  8161 D MainActivity: testIdleHandler() start
09-23 23:21:36.340  8161  8161 D MainActivity: testIdleHandler() end
09-23 23:21:36.340  8161  8161 D MainActivity: testSendDelayedMessages() start
09-23 23:21:36.340  8161  8161 D MainActivity: testSendDelayedMessages() end
09-23 23:21:36.729  8161  8161 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:21:38.844  8161  8161 D MainActivity: Main thread message occurred & what:1
...
09-23 23:21:38.845  8161  8161 D MainActivity: Main thread message occurred & what:10

上面的 queueIdle() 返回了 false 确保处理后 Handler 得到了移除。

但如果返回 true 且没有调用 removeIdleHandler() 的话,后续空闲的时候 Handler 还会被执行,这点需要留意!

    private fun testIdleHandler() {
        mainHandler.looper.queue.addIdleHandler {
            ...
            true // false
        }
    }

queueIdle() 因为没被移除的缘故被回调了多次,源自于 Looper 没执行完一次 Message 后发现尚无 Message 的时候都会回调一遍 IdleHandler,直到队列一直没有 Message 到来。

09-23 23:24:04.765  8226  8226 D MainActivity: onCreate()
09-23 23:24:05.010  8226  8226 D MainActivity: testIdleHandler() start
09-23 23:24:05.011  8226  8226 D MainActivity: testIdleHandler() end
09-23 23:24:05.368  8226  8226 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:24:05.370  8226  8226 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:24:05.378  8226  8226 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:24:05.381  8226  8226 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:24:05.459  8226  8226 D MainActivity: testIdleHandler() queueIdle callback

那如果 add 完不移除的 IdleHandler 之后,发送一个延时 Message,那便会导致空闲消息多执行一遍。

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    testIdleHandler()
    sendDelayedMessage(mainHandler, 1)
}
09-23 23:31:53.928  8620  8620 D MainActivity: onCreate()
09-23 23:31:54.042  8620  8620 D MainActivity: testIdleHandler() start
09-23 23:31:54.042  8620  8620 D MainActivity: testIdleHandler() end
09-23 23:31:54.272  8620  8620 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:31:54.273  8620  8620 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:31:54.278  8620  8620 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:31:54.307  8620  8620 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:31:54.733  8620  8620 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:31:56.546  8620  8620 D MainActivity: Main thread message occurred & what:1
09-23 23:31:56.546  8620  8620 D MainActivity: testIdleHandler() queueIdle callback

为什么?

queueIdle() 的回调由 MessageQueue#next() 回调。

// MessageQueue.java
  Message next() {
        ...
        // 循环的初次将待处理 IdleHandler 计数置为 -1
        // 保证第一次可以检查 Idle Handler 的存在和调用
        int pendingIdleHandlerCount = -1;
        int nextPollTimeoutMillis = 0;
        for (;;) {
            ...
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                // 队首的 Message 且建立了同步屏障的话,寻找下一个异步 Message
                if (msg != null && msg.target == null) {
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                // 找到了合适的 Message
                if (msg != null) {
                    // 如果当前时间尚早于目标执行时刻
                    // 设置休眠的超时时间,即当前时间与目标时刻的差值
                    if (now < msg.when) {
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        mBlocked = false;
                        // 时间条件满足 Message 出队
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        // 并返回 Message
                        msg.next = null;
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // 队里尚无合适的 Message
                    // 进入无限休眠
                    nextPollTimeoutMillis = -1;
                }
                // 如果正在退出 Looper,结束循环并返回 null
                // 将促使 loop() 退出
                if (mQuitting) {
                    dispose();
                    return null;
                }
                // 如果没有合适的 Message 且 Looper 没有退出
                // 检查是否有 Idle Handler 需要处理
                // 读取 Idle Handler 列表
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                // 如果暂时没有 Idle Handler 需要处理,则进入下一次循环
                // 为使下次循环如果出现新的 Idle Handler 能有机会执行
                // 不重置计数器,仍为初始值 -1
                if (pendingIdleHandlerCount <= 0) {
                    mBlocked = true;
                    continue;
                }
                // 如果 IdleHandler 存在则拷贝到待处理列表
                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }
            // 遍历待处理 Idle Handlers
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null;
                boolean keep = false;
                try {
                    // 逐个回调 queueIdle()
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }
                // 回调返回 false,则将其移除出 Idle 列表
                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }
            // 处理完之后重置 IdleHandler 的计数
            // 保证下次循环不会重复处理 IdleHandler
            pendingIdleHandlerCount = 0;
            nextPollTimeoutMillis = 0;
        }
    }

有几点细节需要留意:


next() 循环的第一次将 count 置为 -1,确保队列空闲的时候必然有机会处理 IdleHandler

如果暂无 IdleHandler 可以处理直接进入下一次循环,并且保留 count 的处置,确保下次循环可以检查是否有新的 IdleHandler 加入进来

IdleHandler 正常处理结束之后,避免下次循环重复处理,会将 count 置为 0,保证下次不再检查。注意:是下次循环,不是永久不检查

结论和应用

结论:

IdleHandler 可以实现 MessageQueue 空闲状态下的任务执行,比如做一些启动时的轻量级初始化任务。但由于其执行的时机依赖于队列的 Message 状态,不太可控,谨慎使用!


应用:AOSP 源码里有不少地方使用了 IdleHandler 机制,比如 ActivityThread 使用它在空闲的状态下进行 GC 回收处理。

// ActivityThread.java
  final class GcIdler implements MessageQueue.IdleHandler {
        @Override
        public final boolean queueIdle() {
            doGcIfNeeded();
            purgePendingResources();
            return false;
        }
    }
  void scheduleGcIdler() {
        if (!mGcIdlerScheduled) {
            mGcIdlerScheduled = true;
            Looper.myQueue().addIdleHandler(mGcIdler);
        }
        mH.removeMessages(H.GC_WHEN_IDLE);
    }
    void unscheduleGcIdler() {
        if (mGcIdlerScheduled) {
            mGcIdlerScheduled = false;
            Looper.myQueue().removeIdleHandler(mGcIdler);
        }
        mH.removeMessages(H.GC_WHEN_IDLE);
    }

名词总结

非延时、延时以及插队执行这几种 Message 大家使用较多,无需赘述。但其他几个冷僻的 Message 术语需要总结一下,供大家快速对比和加深理解。

1672155468263.png

结语

上述对于各种 Message 和 IdleHandler 做了演示和原理阐述,相信对于它的细节有了更深的了解。


下面来进行一个简单的总结:


非延时执行 Message:并非立即执行,而是按照请求的时刻进行排队和调度,最终取决于队列的顺序和主线程是否空闲

延时执行 Message:也并非在 Delay 的时刻立即执行,执行时刻受唤醒误差和线程任务阻塞的影响必然晚于 Delay 时刻

插队执行 Mesage:同样并非立即执行,而是每次都将任务放在了队首,达到先执行的目的,但打乱了执行顺序存在逻辑隐患

异步 Message:系统使用居多,App 则需反射,通过这种机制可插队执行同时确保其他 Message 阻塞,学习一下

IdleHandler “Message”:系统多有使用,实现 MessageQueue 空闲状态下的任务执行,但执行时机不可控,最好执行完之后便移除,谨慎使用


相关文章
|
5月前
|
存储 消息中间件 安全
27道 Handler 经典面试题,你能答出多少?
27道 Handler 经典面试题,你能答出多少?
|
2月前
|
存储 前端开发 JavaScript
PixiJS源码分析系列:第四章 响应 Pointer 交互事件(上篇)
PixiJS源码分析系列:第四章 响应 Pointer 交互事件(上篇)
|
3月前
|
消息中间件 前端开发 NoSQL
阿里面试:说说@Async实现原理?
阿里面试:说说@Async实现原理?
32 0
|
5月前
|
前端开发 开发者
【面试题】手写async await核心原理,再也不怕面试官问我async await原理
【面试题】手写async await核心原理,再也不怕面试官问我async await原理
141 1
|
5月前
|
前端开发
【源码共读】如何优雅的处理 Promise 的错误
【源码共读】如何优雅的处理 Promise 的错误
83 0
|
前端开发
前端学习案例13-promise源码实现5
前端学习案例13-promise源码实现5
62 0
前端学习案例13-promise源码实现5
|
前端开发
前端学习案例12-promise源码实现3
前端学习案例12-promise源码实现3
56 0
前端学习案例12-promise源码实现3
|
前端开发
前端学习案例11-promise源码实现2
前端学习案例11-promise源码实现2
67 0
前端学习案例11-promise源码实现2
|
前端开发 JavaScript
手写async await的 20 行最简实现,阿里面试热门题
如果让你手写async函数的实现,你是不是会觉得很复杂?这篇文章带你用20行搞定它的核心。
|
API 调度
万字复盘 Handler 中各式 Message 的使用和原理(1)
万字复盘 Handler 中各式 Message 的使用和原理(1)
万字复盘 Handler 中各式 Message 的使用和原理(1)