【问题标题】:Is there a method/function in JS that fires promises one by one, synchronously? [duplicate]JS 中是否有一个方法/函数可以同步地一一触发承诺? [复制]
【发布时间】:2022-06-10 17:51:43
【问题描述】:

我的意思是,是否有类似 Promise.all 的东西,只是方法一个接一个地依次执行。还是留给自己制作自定义方法

const getUsersIds = (): Promise<any> => API.Users.getUsersIds().then(action((res) => (state.request.userIds = res))); 

const getUsers = (): Promise<any> => API.Users.getUsers(state.request).then(action((res) => (state.users = res))); 



Promise.all([getUsersIds, getUsers]) // - general row

在这种情况下,主要的命令是,我必须等到 getUsersIds (1) 被执行,然后根据ids 在这些用户中,使用 getUsers (2) 方法获取用户对象

【问题讨论】:

  • 是的,它的 then 方法在 promise 或 async/await 上
  • @Jamiec,你是多么有趣和机智。

标签: javascript reactjs typescript


【解决方案1】:

操作

...主要的问题是,JS中是否有这样的功能,我并不总是想写一个async/await函数,我想要更短更方便的东西

那么,不是 OP 正在寻找的,是对延迟序列中未知数量的 Promise(异步函数)的通用处理吗?

如果是这种情况,可以通过例如turning a list/array of promises into an async generator。实现应该与此类似...

async function* createDeferredValuesPool(asyncFunctions) {
  let asyncFct;
  while (asyncFct = asyncFunctions.shift()) {

    yield (await asyncFct());
  }
}

用法看起来类似于 ...

const deferredValuesPool =
  createDeferredValuesPool([promise1, asynFunction2, asynFunction3]);

for await (const value of deferredValuesPool) {
  // do something e.g. based on `value`
}

运行示例代码以证明上面所说/建议的内容。

// a just example specific helper which creates async functions.
function createDeferredValueAction(value, delay) {
  return async function () {
    return await (
      new Promise(resolve => setTimeout(resolve, delay, value))
    );
  };
}


// the proposed helper which creates an async generator.
async function* createDeferredValuesPool(asyncFunctions) {
  let asyncFct;
  while (asyncFct = asyncFunctions.shift()) {

    yield (await asyncFct());
  }
}

// helper task which creates a list of async functions.
const deferredValueActions = [
  ["a", 2000],
  ["b", 3000],
  ["c", 1000],
].map(([value, delay]) =>
  createDeferredValueAction(value, delay)
);

// the OP's actual task(s)

// create an async generator ...
const deferredValuesPool =
  createDeferredValuesPool(deferredValueActions);

(async () => {
  // ... and iterate over it.
  for await (const value of deferredValuesPool) {
    console.log({ value });
  }
})();
.as-console-wrapper { min-height: 100%!important; top: 0; }

编辑

从上面的延迟值生成器示例中学习可以回到 OP 的原始代码,由于其简单性,仍然最好由另一个 then 处理。

但在某些情况下,必须链接未知数量的异步函数,每个函数都依赖于之前调用的函数的结果。因此,必须为 thenables 提出一个通用的解决方案。

一个可能的解决方案是将异步生成器函数 createDeferredValuesPool 重构为 createThenablesPool,其中更改很小...

// the OP's original TS code
// stripped and formatted into JS

// const getUsersIds = () =>
//   API.Users.getUsersIds().then(
//     action(res => state.request.userIds = res)
//   );
// const getUsers = () =>
//   API.Users.getUsers(state.request).then(
//     action(res => state.users = res)
//   );

// rewrite both above getters into (thenable)
// async functions which each returns its result.

async function getUsersIds() {
  // return (await API.Users.getUsersIds());

  // fake it for demonstration purpose only.
  return (await new Promise(resolve =>
    setTimeout(resolve, 1500, [123, 456, 789])
  ));
}
async function getUsers(userIds) {
  // return (await API.Users.getUsers({ userIds }));

  // fake it for demonstration purpose only.
  return (await new Promise(resolve =>
    setTimeout(resolve, 1500, userIds

      // prove that the `userIds` result
      // from the before API call got
      // passed to the next/this one.
      .map(function (id, idx) {
        return {
          id,
          name: this[idx],
        };
      }, ['foo', 'bar', 'baz'])
    )
  ));
}

// the proposed helper which creates
// an async generator of thenables.
async function* createThenablesPool(asyncFunctions) {
  let result;
  let asyncFct;
  while (asyncFct = asyncFunctions.shift()) {

    result = await asyncFct(result);
    // debugger;

    yield result;
  }
}

// the OP's actual task(s)
(async () => {

  for await (
    const value of createThenablesPool([getUsersIds, getUsers])
  ) {
    console.log({ value });
  }
})();
.as-console-wrapper { min-height: 100%!important; top: 0; }

【讨论】:

    【解决方案2】:

    您只需要等待第一次调用完成,然后再进行第二次调用 - 这里不需要魔法/特殊方法 - 它只是标准异步代码

    const getUsersIds = (): Promise<any> => API.Users.getUsersIds();
    const getUsers = (userIds): Promise<any> => API.Users.getUsers(userIds);
    
    const userIds = await getUserIds();
    const users = await getUsers(userIds);
    action(users);
    

    您也可以使用then 语法来做同样的事情

    const getUsersIds = (): Promise<any> => API.Users.getUsersIds();
    const getUsers = (userIds): Promise<any> => API.Users.getUsers(userIds);
    
    getUserIds.then(userIds => getUsers(userIds)).then(action);
    

    【讨论】:

    • 作为一项规则,我会这样做,但同样,主要问题是,JS 中是否有这样的函数,我并不总是想写一个 async / await 函数,我想要更短的更方便
    • @LevMyndra 你想要比 5 行代码更短、更方便的东西吗?!抱歉,帮不了你
    • @Jamiec 我在想作者是在询问可扩展的解决方案。这个then 链可以用于 2-3 个承诺,但如果你有 20-30 个呢?我怀疑你会用手输入所有的链条
    猜你喜欢
    • 2017-11-03
    • 2013-11-25
    • 2023-02-08
    • 1970-01-01
    • 2023-03-11
    • 2014-01-06
    • 2018-06-14
    • 1970-01-01
    • 2019-02-15
    相关资源
    最近更新 更多