【问题标题】:Synchronous callback with different timeout不同超时的同步回调
【发布时间】:2019-08-05 12:57:00
【问题描述】:

我正在尝试使用回调函数进行控制台,它本身是 setTimeout 函数中的回调函数。如何才能得到有序的结果?

我希望调用 f1 的回调,然后调用 f2,最后调用 f3,无论它们的计时器如何。

let f1 = (cb) => { 
    setTimeout(() => {
        cb(null, {a: 1})
    },100)
}

let f2 = (cb) => { 
    setTimeout(() => {
        cb(null, {a: 2})
    },50)
}

let f3 = (cb) => { 
    setTimeout(() => {
        cb(null, {a: 3})
    },10)
}

function parallelConsole(arr, cb) {
    let result = [];
    arr.forEach(func => {
        func((temp, val) => {
            console.log(val)
            result.push(val)
            if(arr.length === result.length) {
                cb(result)
            }      
        })
    })
}

parallelConsole([f1, f2, f3], (res) => {
    console.log(res) //[{a: 3}, {a: 2}, {a: 1}]
})

预期结果:[{a: 1}, {a: 2}, {a: 3}]

实际结果:[{a: 3}, {a: 2}, {a: 1}]

【问题讨论】:

  • 你会并行执行还是顺序执行? f3 的超时时间比 f2 的超时时间短,f2 的超时时间比 f'3 的超时时间短。结果很明显 f3,f2,f1。
  • @Alessandro 是的,我希望结果是 f1,f2,f3。这就是我在这里的原因。
  • @Alessandro 无论计时器如何,我都希望 f1 在结果 [0] 处。
  • @StefanN 在这里,我按照您分享的链接中的说明进行了操作。我仍然没有得到预期的结果。链接:jsfiddle.net/0v923pLq/1

标签: javascript node.js asynchronous settimeout


【解决方案1】:

如果您确实必须使用回调并且这是针对与生产相关的项目,那么使用async.js 是一种选择吗?它提供了一些非常有用的功能(.each 可能正是您想要的)。

我希望调用 f1 的回调,然后调用 f2,最后调用 f3,无论它们的计时器如何。

我对此有点困惑。如果有超时,那么回调将在指定的时间过去后被调用。或者你想以有序的方式(1、2、3)console.log结果而不考虑回调何时被调用?

编辑:我已经修复了一些你的代码,所以我认为它可以满足你的需求。来自f1, f2, f3promise 未返回。此外,正如 cmets 中所指出的,使用 Promise.all 可以确保在所有承诺都已实现后调用最终回调。

const f1 = (cb) => {
  return new Promise ((resolve) => setTimeout(() => {
    resolve(cb(null, { a: 1 }))
  }, 100))
};

const f2 = (cb) => {
  return new Promise ((resolve) => setTimeout(() => {
    resolve(cb(null, { a: 2 }))
  }, 50))
};

const f3 = (cb) => {
  return new Promise ((resolve) => setTimeout(() => {
    resolve(cb(null, { a: 3 }))
  }, 10))
};

function parallelConsole(arr, cb) {
  return Promise.all(arr)
    .then((values) => {
      cb(null, values);
    });
}

const log = (err, data) => {
  if (err) {
    // TODO: handle properly
    return console.log(err);
  }

  return data;
};

parallelConsole([f1(log), f2(log), f3(log)], (err, res) => {
  console.log(res)
});

【讨论】:

  • 嗨,丹尼,欢迎来到 SO!我了解您没有足够的积分来发表评论,但确实不是答案。
  • 最好还是全力以赴地履行 Promise 并在此处放弃 cb :)
【解决方案2】:
let f1 = (cb) => {
  setTimeout(() => {
    cb(null, { a: 1 });
  }, 100);
};

let f2 = (cb) => {
  setTimeout(() => {
    cb(null, { a: 2 });
  }, 50);
};

let f3 = (cb) => {
  setTimeout(() => {
    cb(null, { a: 3 });
  }, 10);
};

function parallelConsole(arr, cb) {
  let result = [];
  let offset = 0;

  const next = () => {
    if (arr.length === result.length) {
      return cb(result);
    }
    arr[offset]((temp, val) => {
      console.log(val);
      result.push(val);
      offset += 1;
      next();
    });
  };
  next();
}

parallelConsole([f1, f2, f3], (res) => {
  console.log(res); //[{a: 3}, {a: 2}, {a: 1}]
});

【讨论】:

    【解决方案3】:

    如果您愿意全力以赴 Promises 而不是回调,代码会变得更加优雅:

    // Promisified delay. Resolves with the given optional value after msec.
    const delay = (msec, value) =>
      new Promise(resolve => setTimeout(() => resolve(value), msec));
    
    // Call `cb` on the resolved value of `p`; resolve with the same value.
    const tapPromise = (p, cb) =>
      p.then(v => {
        cb(v);
        return v;
      });
    
    // Factories for the slow promises
    const f1 = () => delay(100, { a: 1 });
    const f2 = () => delay(50, { a: 2 });
    const f3 = () => delay(10, { a: 3 });
    
    // Create three promises and tap them with console.log.
    // (They start executing right away, not when they're waited on.)
    const promises = [f1(), f2(), f3()].map(p => tapPromise(p, console.log));
    
    // Wait for all three promises to resolve, then log the results.
    // Promise.all guarantees the order is the same as with the original promises.
    Promise.all(promises).then(results => {
      console.log(results);
    });
    

    【讨论】:

      猜你喜欢
      • 2012-06-30
      • 2011-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多