2017-08-30 39 views
0

在承诺中,我需要调用并处理不确定数量的异步API响应,然后在另一个承诺内或在承诺之后单独调用它们,但在另一承诺之前,因此执行顺序受到尊重。动态Javascript承诺的模式

var promiseA = function() { 
    return new Promise(function(resolve, reject) { 
    // 1. Establish objects needed from one API endpoint 
    // 2. Call API endpoint for each object and parse 
    // 3. Only then continue to next promise 
    } 
} 

var finalPromise = function() { 
    return new Promise(function(resolve, reject) { 
    // 
    } 
} 

promiseA() 
.then(finalPromise) 

因此,在promiseA中,我找出需要从API中分别轮询多少个对象。每个请求当然是异步的。我需要进行这些调用并在最终承诺被调用之前处理响应。

我很努力地通过承诺来确定一个模式,我可以动态地创建这些承诺,并且只允许最终承诺在不确定和异步执行和处理后执行。我已经与其他语言一起工作,但我很努力地在Promise中看到它。

任何帮助表示赞赏。

+0

在任何情况下,每一个“呼叫API端点”应该返回承诺本身,'promiseA'不应该使用['Promise' constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-要避免的 - 它)。 – Bergi

+0

目前还不清楚你的代码应该做什么。我们不能只给你一个通用的函数promiseA(){return Promise.all(establishEndpointsArr()。map(callEndpoint)); }' – Bergi

回答

0

我已经更改了以下注释的答案。既然,你提到ES6承诺我会坚持。我们可能关心的回调有两种基本类型。

  1. DOM负载或其他一次性事件回调(在window.onload等)
  2. 异步方法回调(AJAX调用,setTimout等)

由于,

1 .DOM加载或其他一次性事件

var p = new Promise(function(res, rej) { 
     window.onload = res(); 
};  

2.Plain回调:这些回调是不合作的符合惯例。例如的setTimeout

var p = new Promise(function(res, rej){ 
    setTimeout(function() { 
     //your business/view logic 
     success? res():rej(); //if successful resolve else reject 
    }, 2000); 
}); 

在每种上述情况下的承诺(VAR P)可以缠绕到由函数返回。

var myAsyncMethod = function() {  
    var p = new ... // as mentioned in 1 or 2 
    return p; 
} 

然后使用:

myAsyncMethod() 
.then(function(){/* success-handler */}) 
.catch(function(/* failure-handler */)); 

具体到你的问题,你可能有很多这样的方法:

function baseAJAXCall (url) { 
    new Promise(functoin(rej, res) { 
     $.get(url, function(err, data){ 
      if(err) { 
       rej(); 
      } 
      else { 
       resolve(data); 
      } 
     }); 
    } 
}; 

function callAPIEndpoint(url) { 
    return baseAJAXCall(url); 
} 

function finalPromiseHandler() { 
    //your final business/view logic 
} 

//USAGE 
callAPIEndpoint('/my-first-call') 
.then(function(data){ 
    var promiseArray = data.map(function(item){ 
     return baseAJAXCall(item.url); 
    }); 
    return Promise.all(promiseArray); 
}) 
.then(finalPromiseHandler) 
.catch(function(){ 
    console.log('.error-message.'); 
}); 

编号:

  1. How do I convert an existing callback API to promises?。从下面的评论

  2. http://www.datchley.name/es6-promises/

  3. 链接。

--- OLD答:请忽略---

我熟悉这个库:https://github.com/kriskowal/q。而且,您可以使用q.allq.allSettled结构来完成此操作。可能是你正在寻找的。

通常情况下,模式是创建一个返回承诺的函数。

function someAsyncFuncName1(url) { 
    var def = q.defer(); 
    //async function 
    $.get(url, function(err, data){ //suppose 
     if(err){ 
      def.reject(); 
     } 
     else { 
      def.resolve(data); //pass the data to the .then() handler. 
     } 
    }); 
    return def.promise; 
} 

function someAsyncFuncName2() { 
    var def = q.defer(); 
    //async function 
    setTimeout(function(){ //suppose 
     //do something 
     if(good) { 
      def.resolve(); 
     } else { 
      def.reject(); 
     } 
    }, 1000); //arbitrary timeout of 1 second 
    return def.promise; 
} 

用法:

q.all([someAsyncFuncName1('/api-1'), someAsyncFuncName2()]) 
.then(function() { 
    //final handler 
}); 

在思想的类似的线,如果你想等待所有承诺返回一个可以使用q.allSettled()

希望这会有所帮助。

--- EOF OLD答案---

+1

避免'someAsyncFuncName1'中的[deferred antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it) ! – Bergi

+1

'q.defer'被认为是反模式[The Deferred anti-pattern](https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns#the-deferred-anti-pattern)。如果你真的需要创建一个新的Promise,你应该使用常规的'new Promise((resolve,reject)=> {})'模式。 –

+0

谢谢你的评论。我将编辑答案提到这一点。 – 82Tuskers

0

首先,如果PromiseA使用异步函数不返回的承诺,就需要promisify他们。你可以用Promise的构造函数来做到这一点,但是使用类库比如bluebird和promisify方法好得多。

让我们想象一下,我们有两个功能getUserIdsAsyncgetUserAsync。第一个返回用户ID列表,getUserAsync返回用户数据userId。你需要通过他们的ID获得用户列表。的PromiseA的代码可能看起来如此:

​​
+0

'。那么(userIds => {userIds = [1,2,3];'你确定吗?* SyntaxError:正式参数redeclaration userIds * –

+0

@JaromandaX是的,你说得对,谢谢。 – alexmac

0

下面的片断显示,而无需使用任何外部库像蓝鸟的解决方案。它遵循你的问题中的代码片段(这似乎比需要更复杂)。

您必须收集数组中的所有api promisses。然后你可以打电话Promise.all()获得所有api promisses结束的承诺。然后你可以做一些最后的东西,比如分析每个承诺的结果,然后继续。

function getRandomInt(min, max) { 
    return Math.floor(Math.random() * (max - min + 1)) + min; 
} 

var apiEndpoint = function (name) { 
    return new Promise((resolve, reject) => { 
    setTimeout(() => resolve('API ' + name + ' job done'), 1000); 
    }); 
} 

var promiseA = function() { 
    return new Promise((resolve, reject) => { 
    const promisses = []; 
    for (var i=1; i < getRandomInt(3,6); i++) { 
     // 1. Establish objects needed from one API endpoint 
     promisses.push(apiEndpoint('This is number ' + i)); 
    } 
    Promise.all(promisses).then(results => { 
     // do final stuff 
     for (const s of results) { 
     // 2. Call API endpoint for each object and parse 
     console.log(s); 
     } 
     // continue ... 
     // 3. Only then continue to next promise 
     resolve('now it is finished'); 
    }).catch(err => reject(err)); 
    }); 
} 

var finalPromise = function() { 
    return new Promise((resolve, reject) => { 
    console.log('finalPromise'); 
    resolve(); 
    }); 
} 

promiseA() 
    .then(() => finalPromise()) 
    .catch(err => console.log(err)); 

请记住,此解决方案不容易阅读。使用外部库或减少promisses可以提高可读性。也许你应该看看异步/等待模式,以获得更好(可读)的解决方案。

这里是异步/等待下一个解决方案:

function getRandomInt(min, max) { 
    return Math.floor(Math.random() * (max - min + 1)) + min; 
} 

const apiEndpoint = function (name) { 
    return new Promise((resolve, reject) => { 
    setTimeout(() => resolve('API ' + name + ' job done'), 1000); 
    }); 
} 

async function promiseParallel() { 
    const promisses = []; 
    for (let i = 1; i < getRandomInt(3,6); i++) { 
    promisses.push(apiEndpoint('This is number ' + i)); 
    } 
    for (const p of promisses) { 
    const x = await p; 
    console.log(x); 
    } 

    return ('everything is done'); 
} 

promiseParallel().then(result => { 
    console.log(result); 
}).catch(err => console.log(err)); 

如果你想按顺序拨打promisses你可以替换为:

async function promiseSequ() { 
    for (let i = 1; i < getRandomInt(3,6); i++) { 
    const x = await apiEndpoint('This is number ' + i); 
    console.log(x); 
    } 
    return ('everything is done'); 
}