關於Promise和async聲明的區別

題目

可以添加任務,任務包含任務數據,任務延遲觸發的等待時間。
在任務到達觸發時間點時,自動觸發執行此任務。
隊列中任務保持先進先出原則:假設 A 任務的觸發等待時間爲 X,B 任務的觸發等待時間爲 Y,B 在 A 之後被添加入隊列,則 A 的前驅任務執行完成後等待時間 X 後,才執行 A,同理在 A 執行完成後,等待時間 Y,才執行 B。

思路過程

1.Java上線

讀題目就是延時隊列的特徵,Java有鎖,有多線程,寫起來多方便

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class HandWritingQueue {
    public static void main(String[] args) {
        final BlockingQueue<DelayedElement> deque = new DelayQueue<>();
        Runnable producerRunnable = new Runnable() {
            int i = 10;
            public void run() {
                while (true && i>0) {
                    try {
                        --i;
                        System.out.println("producing "+i+",wait "+i+" seconds");
                        deque.put(new DelayedElement(1000 * i, "i=" + i));
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        Runnable customerRunnable = new Runnable() {
            public void run() {
                while (true) {
                    try {
                        System.out.println("consuming:" + deque.take().msg);
                        //Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        Runnable getSize= new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("size="+deque.size());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        };

        Thread thread1 = new Thread(producerRunnable);
        thread1.start();

        Thread thread2 = new Thread(customerRunnable);
        thread2.start();

        Thread thread3 = new Thread(getSize);
        thread3.start();

    }

        static class DelayedElement implements Delayed {

        private final long expire;
        private final String msg;

        public DelayedElement(long delay, String msg) {
            this.msg = msg;
            expire = System.currentTimeMillis() + delay;
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }
        @Override
        public int compareTo(Delayed o) {
            return  -1;//FIFO
        }
    }
}

2.Node上線

被提醒該題目可以用node實現,且不需要藉助redis來做,然後我上手就是一把操作:

'use strict'
class DelayElement {
  constructor(data, expire) {
    this.data = data;
    this.expire = expire;//second
  }
}
const delayArray = [];

//push two element in delayArray
delayArray.push(new DelayElement(1, 2));
delayArray.push(new DelayElement(2, 1));
let length = delayArray.length;

let time_cnt = 0;
while (delayArray.length > 0) {
  let de = delayArray.shift();
  time_cnt += de.expire;//serial
  (function () {
    setTimeout(() => {
      console.log('expire data is :' + de.data + ',expire time is :' + de.expire);
    }, time_cnt * 1000);
  })();
}

我以爲設計的考點也就是立即執行函數,延時的使用,但是這裏的for循環是個僞串行,實際上是併發的,也爲第三步的修改提供了bug

3.Promise時代

一開始我是想把async函數放進去,寫了如下的代碼:

'use strict'
const delayArray = [];
const daPush = (data, expire) => {
  delayArray.push(async () =>  {
    setTimeout(() => {
      console.log('data is ' + data + ' and expire is ' + expire);
    }, expire * 1000);
  });
}
daPush(1, 4);//2 seconds
daPush(2, 5);

(async () => {
  for (const da of delayArray) {
    await da();
  }
})();

發現代碼還是串行的,然後查了一下可能的問題(以下爲個人猜測,歡迎指正)async聲明的函數會包裝成Promise不假,但是for循環會併發去執行await中的async

4.正解

promise執行會阻塞主線程

'use strict'
const delayArray = [];
const daPush = (data, expire) => {
  delayArray.push(() => new Promise((resolve,reject) => {
    setTimeout(() => {
      if(data)
      {
        console.log('data is ' + data + ' and expire is ' + expire);
        resolve(true);
      }
      else{
        reject('there is nodata');
      }
    }, expire * 1000);
  }));
};
daPush(1, 4);//2 seconds
daPush(2, 5);

(async () => {
  for (const da of delayArray) {
    da().then((value)=>{
      // console.log(value);
    }).catch((value)=>{
      console.log(value);
    });
    //沒有28-33,只35行也可以
    // await da();
  }
})();
發佈了82 篇原創文章 · 獲贊 6 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章