当前位置: 首页 > 面试题库 >

从反复调用的承诺返回服务中获取最新数据

戎志勇
2023-03-14
问题内容

我有一个角度服务,可以返回从服务器获取的数据的承诺。在固定的时间间隔内多次请求此数据,以使显示保持最新。有时响应速度可能很慢(最多10秒),如果两个请求重叠并且第一个请求最后响应,我将获取应用程序中显示的过期信息。时间线如下所示:

- first request
Req ---------------------> Res
- second request
      Req -------> Res

目前,我为请求保留一个计数器,使.then函数关闭该请求,如果该数据太旧,则将其丢弃。我想知道那里的一个Promise库是否已经做到了,或者是否有一种标准的方法来做到这一点。

我也已经将响应时间戳添加到返回的对象,或者以某种方式使用RxJs之类的方式,但是我没有用它来知道它是否以某种方式适用。


问题答案:

TL&DR: 我们在这里发明可撤销的承诺。

好吧。一些基础设施。这是您真正需要的典型示例,Promise.cancel()但是ES6本机Promise中没有此示例。作为一个与图书馆无关的人,我只是继续通过Promise子类别发明一个。

以下函数可以保证,可以通过添加一个不可枚举且不可配置的属性(称为)来使其可取消。__cancelled__它还为其属性链添加.then().cancel()方法,而无需修改Promise.prototype。由于可取消的Promise对象的原型的原型是Promise.prototype,我们的可取消的Promise可以访问所有Promise事物。啊..在我忘记之前;可取消原型的then方法还返回可取消承诺。

function makePromiseCancellable(p){
  Object.defineProperty(p,"__cancelled__", {        value: false,
                                                 writable: true,
                                               enumerable: false,
                                             configurable: false
                                           });
  Object.setPrototypeOf(p,makePromiseCancellable.prototype);
  return p;
}

makePromiseCancellable.prototype = Object.create(Promise.prototype);
makePromiseCancellable.prototype.then   = function(callback){
                                            return makePromiseCancellable(Promise.prototype.then.call(this,function(v){
                                                                                                             !this.__cancelled__ && callback(v);
                                                                                                           }.bind(this)));
                                          };
makePromiseCancellable.prototype.cancel = function(){
                                            this.__cancelled__ = true;
                                            return this;
                                          };

因此,我们有一个称为的实用程序函数getAsyncData(),它向我们返回标准的ES6承诺,该承诺在2000毫秒内解析。我们将从此函数中获得两个promise,并将它们变成可取消的promise,称为cp0cp1。然后我们将以cp01000毫秒的速度取消,然后看看会发生什么。

function getAsyncData(){

  var dur = 2000;

  return new Promise((v,x) => setTimeout(v.bind(this,"promise id " + pid++ + " resolved at " + dur + " msec"),dur));

}



function makePromiseCancellable(p){

  Object.defineProperty(p,"__cancelled__", {        value: false,

                                                 writable: true,

                                               enumerable: false,

                                             configurable: false

                                           });

  Object.setPrototypeOf(p,makePromiseCancellable.prototype);

  return p;

}



makePromiseCancellable.prototype = Object.create(Promise.prototype);

makePromiseCancellable.prototype.then   = function(callback){

                                            return makePromiseCancellable(Promise.prototype.then.call(this,function(v){

                                                                                                             !this.__cancelled__ && callback(v);

                                                                                                           }.bind(this)));

                                          };

makePromiseCancellable.prototype.cancel = function(){

                                            this.__cancelled__ = true;

                                          };

var pid = 0,

    cp0 = makePromiseCancellable(getAsyncData());

    cp1 = makePromiseCancellable(getAsyncData());

cp0.then(v => console.log(v));

cp1.then(v => console.log(v));



setTimeout(_ => cp0.cancel(),1000);

哇..!太棒了。cp1在2000毫秒时解决,而cp0在1000 毫秒时已取消。

现在,由于我们拥有基础结构,因此可以使用它来解决您的问题。

以下是我们将使用的代码;

function getAsyncData(){
  var dur = ~~(Math.random()*9000+1001);
  return new Promise((v,x) => setTimeout(v.bind(this,"promise id " + pid++ + " resolved at " + dur + " msec"),dur));
}

function runner(fun,cb){
  var promises = [];
  return setInterval(_ => { var prom = makePromiseCancellable(fun());
                            promises.push(prom);
                            promises[promises.length-1].then(data => { promises.forEach(p => p.cancel());
                                                                       promises.length = 0;
                                                                       return cb(data);
                                                                     });
                          },1000);
}

var pid = 0,
    sid = runner(getAsyncData,v => console.log("received data:", v));
setTimeout(_=> clearInterval(sid),60001);

这很基本。该runner()功能正在完成工作。它通过调用来每1000毫秒请求一次承诺getAsyncData()getAsyncData()但是这次的功能会给我们一个承诺,它将在1〜10秒内解决。之所以如此,是因为我们希望在某些先前收到的承诺仍处于未解决状态时,某些稍后的承诺能够解决。就像您的情况一样。好;
使接收到的promise可以取消后,该runner()函数将其推入promises数组。仅在将promise推送到promises数组之后,才将then指令附加到其上,因为我们希望数组仅保留主要的promise,而不是从then舞台返回的那些promise
。哪个诺言首先解决并称其为then方法,将首先取消数组中的所有promise,然后清空数组;只有在此之后,才会调用提供的回调函数。

现在让我们来看整个过程。

function makePromiseCancellable(p){

  Object.defineProperty(p,"__cancelled__", {        value: false,

                                                 writable: true,

                                               enumerable: false,

                                             configurable: false

                                           });

  Object.setPrototypeOf(p,makePromiseCancellable.prototype);

  return p;

}



makePromiseCancellable.prototype = Object.create(Promise.prototype);

makePromiseCancellable.prototype.then   = function(callback){

                                            return makePromiseCancellable(Promise.prototype.then.call(this,function(v){

                                                                                                             !this.__cancelled__ && callback(v);

                                                                                                           }.bind(this)));

                                          };

makePromiseCancellable.prototype.cancel = function(){

                                            this.__cancelled__ = true;

                                            return this;

                                          };



function getAsyncData(){

  var dur = ~~(Math.random()*9000+1001);

  return new Promise((v,x) => setTimeout(v.bind(this,"promise id " + pid++ + " resolved at " + dur + " msec"),dur));

}



function runner(fun,cb){

  var promises = [];

  return setInterval(_ => { var prom = makePromiseCancellable(fun());

                            promises.push(prom);

                            promises[promises.length-1].then(data => { promises.forEach(p => p.cancel());

                                                                       promises.length = 0;

                                                                       return cb(data);

                                                                     });

                          },1000);

}



var pid = 0,

    sid = runner(getAsyncData,v => console.log("received data:", v));

setTimeout(_=> clearInterval(sid),60001);

runner如果不停止,该函数将无限期运行。因此,在60001毫秒时,我通过清除了它clearInterval()。在此期间,将收到60个承诺,并且只有第一个解析器会通过取消所有
先前
收到的当前承诺(包括尚未解决的承诺)来调用提供的回调,这些承诺包括我们promises数组中第一个解决承诺后收到的承诺。但是,由于预计这些后来的承诺将包含更多的新数据,因此您可能希望取消它们。然后,我认为代码中的以下较小更改在使用最新数据更频繁地刷新屏幕方面会更好。

function makePromiseCancellable(p){

  Object.defineProperty(p,"__cancelled__", {        value: false,

                                                 writable: true,

                                               enumerable: false,

                                             configurable: false

                                           });

  Object.setPrototypeOf(p,makePromiseCancellable.prototype);

  return p;

}



makePromiseCancellable.prototype = Object.create(Promise.prototype);

makePromiseCancellable.prototype.then   = function(callback){

                                            return makePromiseCancellable(Promise.prototype.then.call(this,function(v){

                                                                                                             !this.__cancelled__ && callback(v);

                                                                                                           }.bind(this)));

                                          };

makePromiseCancellable.prototype.cancel = function(){

                                            this.__cancelled__ = true;

                                            return this;

                                          };



function getAsyncData(){

  var dur = ~~(Math.random()*9000+1001);

  return new Promise((v,x) => setTimeout(v.bind(this,"promise id " + pid++ + " resolved at " + dur + " msec"),dur));

}



function runner(fun,cb){

  var promises = [];

  return setInterval(_ => { var prom = makePromiseCancellable(fun());

                            promises.push(prom);

                            promises[promises.length-1].then(data => { var prix = promises.indexOf(prom);

                                                                       promises.splice(0,prix)

                                                                               .forEach(p => p.cancel());

                                                                       return cb(data);

                                                                     });

                          },1000);

}



var pid = 0,

    sid = runner(getAsyncData,v => console.log("received data:", v));

setTimeout(_=> clearInterval(sid),60001);

当然可能会有一些缺陷。我想听听你的想法。



 类似资料:
  • 问题内容: 关于这两个重要来源:NZakas- 承诺链中的归还承诺 和MDN承诺,我想提出以下问题: 每次我们从承诺履行处理程序返回值时,该值如何传递给从同一处理程序返回的新承诺? 例如, 在这个例子中,是一个承诺。也是来自履行处理程序的承诺。但是。取而代之的是神奇地解决(如何?),然后将该值传递给的实现处理程序。即使是这里的句子也令人困惑。 您能给我解释一下这到底是怎么回事吗?我对这个概念感到困

  • 问题内容: 我将慢速的WebSockets服务器包装在AngularJS服务中,然后从我的控制器调用该服务。如果我将回调链接到回调上,则一切正常,所有UI均异步更新。 当我尝试用来清理一团糟的回调时,似乎我的延迟请求从未被调用。我熟悉从Python的Twisted派生的概念,因此我认为从概念上讲一切都应该起作用-但事实并非如此。 这是我能想到的最短的例子,慢速的WebSockets服务器是使用se

  • 问题内容: 我的服务是: 我通过以下方式在我的文件中调用它: 但是,它抱怨这不是一个功能。我不退还已解决的承诺吗? 问题答案: 从您的服务方式: 在您的控制器中:

  • 问题内容: 根据Michal Charemza帖子编辑。 我有一个代表angularui模态对话框的服务: 如果用户单击对话框中的“确定”,则在调用delete方法时将执行。 问题是我无法对此进行单元测试。 这是我的考验。我已经正确注入了q服务,但是我不确定应该从间谍那里返回什么… 但是我正在接受。这意味着…部分没有执行。我想念什么? 问题答案: 要模拟返回承诺的函数,它还需要返回承诺,然后需要将

  • 问题内容: Redux thunk成功调度某些动作后,是否可以从动作创建者那里返回承诺/信号,并解决? 考虑以下动作创建者: 当Redux分派POST_SUCCESS或POST_ERROR操作时,我想在调用 doPost 操作创建者后 在组件中 异步调用某些函数。一种解决方案是将回调传递给动作创建者本身,但这会使代码混乱并且难以掌握和维护。我也可以在while循环中轮询Redux状态,但是那样效率

  • 问题内容: 我正在使用promis模块从请求模块返回我的json数据,但是每次运行它时,它都会为我提供此信息。 我无法正常工作,有人知道这个问题吗?这是我的代码: 问题答案: 许诺是充当未来价值的占位符的对象。您的函数返回该Promise对象。通过将处理程序附加到promise,您可以在promise中获得未来的价值: 这是异步代码,因此,仅能通过处理程序来获得承诺的价值。 修改清单: 在返回的p