繁体   English   中英

在co()函数中的先前承诺之后,Promise.all()不起作用

[英]Promise.all() doesn't work after a previous promise in a co() function

下面的代码正常工作:

"use strict"

const request = require('request-promise-native')
const co = require('co')

function getResults() {
    return co(function *() {
        //yield request('http://www.google.es').then(res => {
        //    console.log('Request 1')
        //})
        const paginatedResources = [
            'http://www.yahoo.com',
            'http://www.gmail.com'
        ]
        const promises = []
        paginatedResources.forEach((uri) => {
            promises.push(request(uri))
        })
        Promise.all(promises).then(function(res) {
            console.log('Request 2 and 3') //Order doesn't matters
        })
    })
}

getResults()

Promise.all()返回期望值,但是如果我取消注释第8行( yield ... ),则Promise.all似乎无法解析(控制台日志2和3消息未出现)。 为什么第一个承诺的解决会影响第二个承诺?

您的函数未返回任何内容:

return co(function *() {
  //let firstPageResponse = yield request(getListConfiguredResource(filterBy)).then((res) => { return res })
  //let paginatedResources = getAllPaginatedResources(firstPageResponse.headers)
  let paginatedResources = [
      'https://api.github.com/users/jvcalderon/gists?per_page=100&page=1',
      'https://api.github.com/users/jvcalderon/gists?per_page=100&page=2',
      'https://api.github.com/users/jvcalderon/gists?per_page=100&page=3'
  ];
  //here you should return something
  return Promise.all(
    paginatedResources.map(
      url => request(getBaseConfiguredResource(url))
    )
  );
})

如果您想要一个预取所有资源的迭代器,则无法返回解析值,因为您不知道使用者何时要调用next()以及消费者何时进行了任何异步处理。 因此,消费者必须履行承诺:

/*
causes a promise returning function not to be called
untill less than max are active
usage example:
max2 = throttle(2);
functions = [fn1,fn2,fn3...fn100];//functions returning promise
params = [param1,param2,param3...param100]
Promise.all(//even though a 100 promises are created, only 2 are active
  functions.map(
    (fn,index)=>
      max2(fn)(params[index])
      .then(...)
  )
)
*/
const throttle =
  (max) =>{
    var que = [];
    var running = 0;
    const wait = function*(resolve,fn,arg){
      return resolve(fn(arg));
    };
    const nextInQue = ()=>{
      const it = que[0];
      que=que.slice(1);
      if(it){
        it.next();
      }
      return true;
    };
    const queItem = (fn,arg)=>
      new Promise(
        (resolve,reject)=>que.push(wait(resolve,fn,arg))
      )
    ;
    return (fn)=>(arg)=>{
      const p = queItem(fn,arg)
        .then(x=>nextInQue() && x)
      ;
      running++;
      if(running<=max){
        nextInQue();
      }
      return p;
    };    
  }
;

/*
result.toPromse(result) 
  if result is type Error a rejected promise is returned
    reject reason is result.val
  if result is of type Value a resolved promise is returned
    resolve is result.val
  else a resolved promise is returned
    resolve value is result
result toResult
  if promise is rejected the rejection is caught
    the promise resolves to a result of type Error
    with val of reject reason
  if promise is resolved
    the promise resolves to a result of type Value
    with val of resolved value
*/
const result = (function(){
  const Error = function(val){this.val=val;}
  const Value = function(val){this.val=val;}
  return {
    toResult:promise =>
      promise.then(
        val => new Value(val)
        ,reject => new Error(reject)
      )
    //a promise resolving in a result (Error or Value)
    ,toPromise:result =>
      result.then(
        x => 
          (x.constructor === Error)
            ?Promise.reject(x.val)
            :(x.constructor === Value)
              ?Promise.resolve(x.val)
              :Promise.resolve(x)
      )
  }
})();

const test = function *() {
  var i = -1;
  //maximal 2 unresolved promises
  const max2 = throttle(2);
  const paginatedResources = [
    '/index.html',
    //causes fetch to return a rejected promise
    'http://ldsjdslfjalksfljasdflkjasdflkjsdljla/error',
    '/index.html'
  ];
  //pre fetch all resources
  const promises = 
    paginatedResources
      .map(
        url =>
          //toResult causes any promise to resolve in a result
          result.toResult(//max2(fetch)(url) gets uncaught in promise
            max2(//maximal 2 active request (can change throttle)
              fetch
            )(url)
          ) 
      )
  ;
  while(++i<promises.length){
    yield promises[i];
  }
}

//consuming the itirator
const it = test();
const consumeNext = () =>{
  var v;
  return (v = it.next()).done
    ?Promise.resolve("we are done")
    //toPromise causes result type to convert in promise
    // that is resolved or rejected based on result
    // being Value or Error
    :result.toPromise(v.value).then(x=>x.text())
}
consumeNext()
  .then(
    x=>console.log("first resouce:",x.length)
    ,reject=>console.warn(reject)
  )
;
consumeNext()
  .then(
    x=>console.log("second resouce:",x.length)
    ,reject=>console.warn(reject)
  )
;
consumeNext()
  .then(
    x=>console.log("third resouce:",x.length)
    ,reject=>console.warn(reject)
  )
;

问题不在代码中。 它正常工作。 我在用于通过Mocha和'chai-as-promised'测试代码的测试套件中发现错误。 我有这样一行:

expect(getResults()).should.eventually.equal("foo")

但是应返回此结果以等待响应:

return expect(getResults()).should.eventually.equal("foo")

添加return语句使测试有效。

暂无
暂无

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

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