简单了解

参阅MDN Promise

  1. Promise 主要用来改进异步编程体验
  2. Promise 有三个状态pendingfullfilledrejected, 执行resolve后pending->fullfilled
  3. fullfilled的 Promise 实例会转入.then()处理;rejected会转入.catch()处理

promise 类的结构

const PENDING = "pending";
const FULLFILLED = "fullfilled";
const REJECTED = "rejected";
 
class MyPromise {
  constructor(executor) {
    this.state = PENDING;
    this.val = undefined; // 成功状态promise值
    this.reason = undefined; // 失败状态下的promise值
    this.onFullfilledCallbacks = []; // 成功回调队列
    this.onRejectedCallbacks = []; // 失败回调队列
    executor(this.resolve.bind(this), this.reject.bind(this)); // 直接执行promise构造函数
  }
 
  resolve(val) {}
  reject(reason) {}
  then(onfullfilled, onrejected) {}
  catch(onrejected) {}
  finally(cb) {}
  static resolve(arg) {}
  static reject(arg) {}
  static all(promises) {}
  static race(promises) {}
}

resolve

resolve(x) {
  if(this.state === PENDING) {
    if (x != null && typeof x === "object" && typeof x.then === "function") {
      x.then(this.resolve.bind(this), this.reject.bind(this));
    }
    else {
      // pending 状态变成fullfilled状态
      this.state = FULLFILLED;
      this.val = x;
      this.onFullfilledCallbacks.forEach(fn => {
        fn(this.val);
      });
    }
  }
}

static resolve

static resolve(arg) {
  return new MyPromise((resolve, reject) => {
    // 判断 arg是否promise
    if(arg !== null && typeof arg ==="object" && typeof arg.then === "function") {
      arg.then(resolve, reject);
    } else {
      resolve(arg);
    }
  })
}

reject

reject(r) {
  if(this.state === PENDING) {
    if(r !== null && typeof r === "object" && typeof r.then === "function") {
      r.then(this.resolve.bind(this), this.reject.bind(this));
    }
    else {
      // pending 状态变为fullfilled状态
      this.state = REJECTED;
      this.reason = r;
      this.onRejectedCallbacks.forEach(fn => fn(this.reason));
    }
  }
}

then

then(onfullfilled, onrejected) {
  onfullfilled = typeof onfullfilled === "function" ? onfullfilled : value => value;
  onrejected = typeof onrejected === "function" ? onrejected : reason => reason;
  return new MyPromise((resolve, reject) => {
    let fullfilled = value => {
      try {
        let x = onfullfilled(value);
        // x为 MyPromise 或 thenable
        if(x !== null && typeof x === "object" && typeof x.then === "function") {
          x.then(resolve, reject);
        } else {
          resolve(x);
        }
      } catch(err) {
        reject(err)
      }
    }
    setTimeout(() => {
      if (this.state === PENDING) {
        this.onFullfilledCallbacks.push(fullfilled);
        this.onRejectedCallbacks.push(rejected);
      }else if(this.state === FULLFILLED) {
        fullfilled(this.val);
      }else {
        rejected(this.reason)
      }
    }, 0);
  })
}

finally

finally (cb) {
  return this.then((x) => {
    // cb 如果 也是 promise
    return MyPromise.resolve(cb()).then(() => x);
  }, (r) => {
    return MyPromise.reject(cb()).then(null, () => x);
  });
}

catch

catch (onrejected) {
  return this.then(null, onrejected);
}

race

static race (promises) {
  return new MyPromise((resolve, reject) => {
    for(let i = 0; i < promises.length; i++) {
      MyPromise.resolve(promises[i]).then((data) => {
        resolve(data);
        return;
      }, (err) => {
        reject(err);
        return;
      });
    }
  })
}

all

static all(promises) {
  return new MyPromise((resolve, reject) => {
    let index = 0;
    let result = [];
    function processValue (i, data) {
      result[i] = data;
      if(++index === promises.length) {
        resolve(result);
      }
    }
    for(let i = 0; i < promises.length; i++) {
      MyPromise.resolve(promises[i]).then((data) => {
        processValue(i, data);
      }, (err) => {
        reject(err);
        return;
      });
    }
  });
}

其它

延迟执行队列

//@vueuse/core useTimeoutFn
async function* makeQueue<T>(jobs: T[], waitGap: number) {
  for (const i of jobs) {
    await new Promise((resolve) => {
      useTimeoutFn(() => {
        resolve(true);
      }, waitGap);
    });
    yield i;
  }
}
 
const repeat = (fn: Function, waitGap: number) => {
  return async function (arg: Bullet[]) {
    for await (const i of makeQueue(arg, waitGap)) {
      fn(i);
    }
  };
};
 
const repeatPlay = repeat(fn.bind(/* your this*/), 3000);
class Queue{
	constructor(){
		this.taskList = []
	}
	task(delay,fn){
		function callback(){
			return new Promise(function(resolve){
				setTimeout(() => {
					fn()
					resolve()
				}, delay);
			})
		}
		this.taskList.push(callback)
		return this
	}
	async start(){
		while(this.taskList.length){
			await this.taskList.shift()()
		}
	}
}
new Queue()
	.task(1000, () => {
		console.log(1)
	})
	.task(2000, () => {
		console.log(2)
	})
	.task(1000, () => {
		console.log(3)
	})
	.start()