简体   繁体   English

如何同步Promise对象?

[英]How To Synchronise Promise Objects?

I have promise objects which need to work synchronize. 我有承诺需要同步的对象。 For example second promise shouldn't work before first one is done. 例如,第二个承诺在第一个承诺完成之前不应该起作用。 If first one rejects first one has to be executed again. 如果第一个拒绝,则必须再次执行。

I have implemented some examples.This one works well. 我已经实现了一些例子。这个很好用。 call getVal, wait 2000ms, return, i++, again call getVal ..... 调用getVal,等待2000ms,返回,i ++,再次调用getVal .....

 getVal() {
       return new Promise(function(resolve, reject) {
      setTimeout(function(){ resolve(19) }, 2000);
         });

     }

async promiseController(){

    for(var i =0;i<5;i++)
      {
        var _val = await this.getVal()
        console.log(_val+'prom');
      }
    }

But I need to control an array of promise objects. 但我需要控制一组promise对象。 What I want to do is that I have a data and I divided it 5 pieces. 我想要做的是我有一个数据,我把它分成5块。 After first part is processed(for example:sent to server) well I want to process second part otherwise I have to process first part again. 在处理完第一部分(例如:发送到服务器)后,我想要处理第二部分,否则我必须再次处理第一部分。

This is the prototype implementation I made 这是我制作的原型实现

  getVal() {
   return new Promise(function(resolve, reject) {
  setTimeout(function(){ resolve(19) }, 2000);
     });

 }

async promiseController(){
  var proms=[]
  for(var i =0;i<5;i++)
    {
      proms.push(this.getVal())
    }

for(var i =0;i<5;i++)
  {
    var _val = await proms[i]
    console.log(_val+'prom');
  }
}

Promises objects in this code works sequentially. 此代码中的Promises对象按顺序工作。 How can i fix the code below so that it works synchronous as first example. 我如何修复下面的代码,以便它作为第一个例子同步工作。

async promiseController(){
  for(const value of array) {
    console.log((await this.getVal(value))+'prom');
  }
}

No need to overcomplicate things. 无需过度复杂化。 Just call await inside the loop and it'll wait for what you want. 只需在循环中调用await ,它就会等待你想要的东西。

As the other answer rightfully said - a promise represents a value and not an operation. 正如另一个答案所说的那样 - 承诺代表一种价值,而不是一种操作。 For operations regular functions are used. 对于操作,使用常规功能。

If you want to ignore failures you can .catch(() => {}) on the promise. 如果你想忽略失败,你可以在.catch(() => {}) If you want to retry until failures - you can refactor retry to a function and use that: 如果要重试直到失败 - 您可以重构重试函数并使用它:

const retry = fn => (...args) => fn(...args).catch(retry(fn));

If your goal is to not "execute the subsequent promises" until the first promise resolves, then you need to keep in mind that promises represent asynchronous activity already in flight . 如果您的目标是在第一个承诺解决之前不“执行后续承诺”,那么您需要记住,承诺代表已经在飞行中的异步活动。 Once the promise exists, it is too late. 一旦承诺存在,就为时已晚。

You need to instead not call the subsequent promise factory methods until the first promise finishes. 在第一个promise完成之前,您需要不要调用后续的promise工厂方法。 Your first example does this by not calling getVal() until the previous promise completes. 您的第一个示例通过在上一个promise完成之前不调用getVal()完成此操作。

So you end up with something like: 所以你最终得到的结果如下:

delay(time) {
    return new Promise(resolve => setTimeout(resolve, time));
}

async promiseController() {
    const factories = [];
    for (let i = 0; i < 5; ++i) {
        factories.push(() => this.getVal());
    }

    for (const f of factories) {
        // keep running this factory until it succeeds
        let success = false;
        while (!success) {
            try {
                const promise = f();
                const result = await f;
                success = true;
                console.log(`result = ${result}`);
            }
            catch (err) {
                console.log("promise failed.  retrying");
                await delay(100);
            }
        }
    }
}

You can use recursion, named function, .then() 你可以使用递归,命名函数, .then()

 var arr = [Promise.resolve("a") , Promise.resolve("b") , Promise.resolve("c")]; var i = 0; var res = []; function foo() { // conditional resolved or rejected promise var n = String(new Date().getTime()).slice(-1); // if `n` < 5 reject `n` , else resolve `n` var curr = n < 5; return curr ? arr[i] : Promise.reject(["rejected", n]) } var p = (function repeat() { var promise = foo(); return promise .then(function(data) { console.log(data); res.push(data); ++i; if (i < arr.length) return repeat() // return `res` array when all promises complete else return res }) .catch(function(err) { console.log(err); if (err[0] === "rejected") return repeat() }) }()); p.then(function(complete) { console.log("complete:", complete) }); 

Well OK. 好吧 I believe for the sake of proper functional programming purposes the async and await thingy should be avoided. 我相信为了正确的函数编程目的,应避免使用asyncawait thingy。 I believe promises are very sufficient. 我相信承诺非常充足。 Yet if you would like to continue coding in C++ ish imperative style then async and await is for you. 然而,如果您想继续使用C ++进行编码,那么asyncawait适合您。

I have promise objects which need to work synchronize. 我有承诺需要同步的对象。 For example second promise shouldn't work before first one is done. 例如,第二个承诺在第一个承诺完成之前不应该起作用。 If first one rejects first one has to be executed again. 如果第一个拒绝,则必须再次执行。

Let me give a little brief on the code below. 让我简单介绍下面的代码。 We have the async() function which takes a data and a callback (error first type). 我们有async()函数,它接受数据和回调(错误优先类型)。 As for demo purposes it will try to invoke the callback with data within 2000ms however there is a timeout at 1000ms. 至于演示目的,它将尝试在2000ms内使用数据调用回调,但是在1000ms处有超时。 So 50-50 it will either invoke the callback with data or error. 所以50-50它将调用带有数据或错误的回调。

So we actually need it to return us a promise so I promisify it with the help of promisify() and it takes async() function and returns me the asyncPro() function. 所以我们实际上需要它给我们一个承诺,所以我在promisify()的帮助下promisify()它,它需要async()函数并返回asyncPro()函数。 Which is in fact same as async() but returns a promise instead. 这实际上与async()相同,但返回一个promise。 So we are expected to use our callback at the then stage. 所以我们期望在then阶段使用我们的回调。

Then comes tryNTimes(data,asyncFun,n = 5) function which takes data, a promisified async function and an integer designating the number of times to try before rejecting it. 然后是tryNTimes(data,asyncFun,n = 5)函数,它接受数据,一个promisified异步函数和一个整数,指定在拒绝它之前尝试的次数。 It's default try count is 5 but you can set it to any value by passing the third argument. 它的默认尝试次数为5,但您可以通过传递第三个参数将其设置为任何值。

As for the last part we have the flowControl() which chains up our promises perfectly by the help of Array.prototype.reduce() . 至于最后一部分,我们有了flowControl() ,它在Array.prototype.reduce()的帮助下完美地链接了我们的promise。

So now we have all our promises chained one after the other and none will fail before trying 5 times. 所以现在我们将所有的承诺一个接一个地链接起来,在尝试5次之前没有一个会失败。

 function promisify(fun){ return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res))); } function async(data, callback){ var dur = Math.floor(Math.random()*2000); setTimeout(_ => callback(false,data),dur); // may resolve before timeout setTimeout(_ => callback("error at " + data),1000); // timeout at 1 sec } function tryNTimes(data,asyncFun,n = 5){ return new Promise((resolve,reject) => { n === 0 && reject("try out fail at 5 tries: " + data); asyncFun(data).then(v => resolve("resolved at countdown " + n + ": " + v)) .catch(e => resolve(tryNTimes(data,asyncFun,--n))); }); } function flowControl(d,f,tc){ return d.reduce((prom,chunk) => prom.then(v => { console.log(v); return tryNTimes(chunk,f,tc); }),Promise.resolve("initial dummy promise")); } var data = ["chunk_1", "chunk_2", "chunk_3", "chunk_4", "chunk_5"], asyncPro = promisify(async); // now our async function returns a promise flowControl(data,asyncPro).then(v => console.log(v)) .catch(e => console.log(e)); 

If you would like to see the "5 times try" errors more frequently please lower the timeout value in async() function. 如果您希望更频繁地看到“5次尝试”错误,请降低async()函数中的超时值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM