8000 执行机制 - 使用Promise实现串行 · Issue #36 · logan70/Blog · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

执行机制 - 使用Promise实现串行 #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
logan70 opened this issue Dec 12, 2019 · 3 comments
Open

执行机制 - 使用Promise实现串行 #36

logan70 opened this issue Dec 12, 2019 · 3 comments

Comments

@logan70
Copy link
Owner
logan70 commented Dec 12, 2019

使用Promise实现串行

Promise原型上的then方法以及Async/Await基本用法大家都熟悉,不作过多介绍。

下面的实现方法本质上也都是基于以上两种用法的拓展。

普通循环

理论上任何循环函数或语法都可实现。

let promise = Promise.resolve()
function runPromisesSerially(tasks) {
  tasks.forEach(task => {
    promise = promise.then(task)
  })
  return promise
}

runPromiseSerially([ task1, task2, ... ])
  .then(() => console.log('finished'))

Array.reduce

上面方法通过循环任务数组,不断在promise后使用.then(nextTask)拼接任务,仔细想想很适合用reduce来实现:

function runPromisesSerially(tasks) {
  return tasks
    .reduce((promise, curTask) => promise.then(curTask), Promise.resolve())
}

Async/Await + 循环

while循环也可实现。

async function runPromisesSerially(tasks) {
  for (const task of tasks) {
    await task()
  }
}

递归

function runPromisesSerially([curTask, ...restTasks]) {
  const p = Promise.resolve()
  if (!curTask) return p
  return p.then(curTask).then(() => runPromisesSerially(restTasks))
}

for await of

需要自己实现可异步迭代的对象供for await of调用。

async function runPromisesSerially([...tasks]) {
  const asyncIterable = {
    [Symbol.asyncIterator]() {
      return {
        i: 0,
        next() {
          const task = tasks[this.i++]
          return task
            ? task().then(value => ({ done: false, value }))
            : Promise.resolve({ done: true })
        }
      }
    }
  }

  for await (val of asyncIterable) {
    // do something
  }
}

for await of + Async Generator

本质上是异步生成器函数()执行会自动生成异步迭代器,然后异步迭代器可配合for await of实现串行运行promises

async function runPromisesSerially(tasks) {
  async function* asyncGenerator() {
    let i = 0
    while (i < tasks.length) {
      const val = await tasks[i]()
      i++
      yield val
    }
  }

  for await (val of asyncGenerator()) {
    // do something
  }
}

Generator

Generator本身只是一个状态机,需要通过调用promise.then()来改变它的状态,实现promises的串行执行。

function runPromisesSerially(tasks) {
  function *gen() {
    for (const task of tasks) {
      yield task()
    }
  }
  const g = gen()
  function next(val) {
    const result = g.next(val)
    if (result.done) return result.value
    result.value.then(val => next(val))
  }
  next()
}
@xiahouwei
Copy link

第一种forEach无法实现串行, 因为forEach是并发的

@logan70
Copy link
Owner Author
logan70 commented May 24, 2022

@xiahouwei 将task跟在原来的Promise后面,每次都会赋值新的Promise,可以实现串行的

@jackieli123723
Copy link
function iteratorPromise(arr){
  let res = Promise.resolve();
  arr.forEach(fn=>{
    res = res.then(()=>fn()) 
  })
}

iteratorPromise(arr);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants
0