Skip to content

Promise

Promise 对象池

js
function promisePool(functions, n) {
  const { length } = functions;
  if (length === 0) {
    return Promise.resolve([]);
  }
  const results = new Array(length);
  const initCount = Math.min(n, length);
  let count = 0;
  let nextIndex = initCount;
  return new Promise(resolve => {
    const nextTask = index => {
      if (index >= length) {
        return;
      }
      functions[index]().then(value => {
        results[index] = value;
        if (++count === length) {
          resolve(results);
        }
        nextTask(nextIndex++);
      });
    };
    for (let i = 0; i < initCount; ++i) {
      nextTask(i);
    }
  });
}

有时间限制的 Promise 对象

js
function timeLimit(fn, t) {
  return function (...args) {
    return new Promise(async (resolve, reject) => {
      let done = false;
      setTimeout(() => {
        if (!done) {
          reject('Time Limit Exceeded');
        }
      }, t);
      try {
        const result = await fn.apply(this, args);
        done = true;
        resolve(result);
      } catch (error) {
        reject(error);
      }
    });
  };
}

并行执行异步函数

js
function promiseAll(functions) {
  const { length } = functions;
  const results = new Array(length);
  let count = 0;
  return new Promise((resolve, reject) => {
    functions.forEach(async (fn, index) => {
      try {
        const res = await fn();
        results[index] = res;
        if (++count === length) {
          resolve(results);
        }
      } catch (error) {
        reject(error);
      }
    });
  });
}

转换回调函数为 Promise 函数

js
function promisify(fn) {
  return async function (...args) {
    return new Promise((resolve, reject) => {
      const cb = (data, error) => {
        if (error) {
          reject(error);
        }
        resolve(data);
      };
      fn.call(this, cb, ...args);
    });
  };
}

并行执行 Promise 以获取独有的结果

js
function promiseAllSettled(functions) {
  const { length } = functions;
  if (length === 0) {
    return Promise.resolve([]);
  }
  const results = new Array(length);
  let count = 0;
  return new Promise(resolve => {
    functions.forEach((fn, i) => {
      fn()
        .then(value => {
          results[i] = { status: 'fulfilled', value };
        })
        .catch(error => {
          results[i] = { status: 'rejected', reason: error };
        })
        .finally(() => {
          if (++count === length) {
            resolve(results);
          }
        });
    });
  });
}

睡眠函数

js
async function sleep(millis) {
  return new Promise(resolve => setTimeout(resolve, millis));
}

两个 Promise 对象相加

js
async function addTwoPromises(promise1, promise2) {
  return new Promise(async resolve => {
    const [res1, res2] = await Promise.all([promise1, promise2]);
    resolve(res1 + res2);
  });
}

延迟每个 Promise 对象的解析

js
function delayAll(functions, ms) {
  return functions.map(fn => {
    return function (...args) {
      return new Promise((resolve, reject) => {
        fn()
          .then(value => {
            setTimeout(() => {
              resolve(value);
            }, ms);
          })
          .catch(error => {
            setTimeout(() => {
              reject(error);
            }, ms);
          });
      });
    };
  });
}

异步加法

js
function asyncAdd(a, b, cb) {
  setTimeout(() => {
    cb(null, a + b);
  }, Math.random() * 1000);
}

const map = new Map();

function sum(...nums) {
  const n = nums.length;
  let count = 0;
  nums.sort((a, b) => a - b);
  const key = nums.join('+');
  if (map.has(key)) {
    return Promise.resolve(map.get(key));
  }
  return new Promise((resolve, reject) => {
    const add = () => {
      if (nums.length >= 2) {
        const a = nums.pop();
        const b = nums.pop();
        asyncAdd(a, b, (error, res) => {
          if (error) {
            reject(error);
          }
          nums.push(res);
          if (++count === n - 1) {
            map.set(key, nums[0]);
            resolve(nums[0]);
          } else {
            add();
          }
        });
      }
    };
    for (let i = 0; i < n / 2; ++i) {
      add();
    }
  });
}

async function total() {
  const res1 = await sum(1, 2, 3, 4, 5, 6, 4);
  const res2 = await sum(1, 2, 3, 4, 5, 6, 4);
  return [res1, res2];
}

console.log(await total());