如何同步调用多次返回 promise 的函数
How to synchronously call multiple times any function which is returning promise
例如,如果我已经有任何缓存的实体 ID,我有 Promise.resolve() 函数,否则它会调用 ajax 来保留实体 ID,然后调用 Promise.resolve() new实体编号
function getReservedEntityId(collectionName) {
//if (!haveCachedIds) {
//make ajax call to reserve new ids
Promise.resolve(newId);
}
return Promise.resolve(cachedId);
};
如何同步调用多次来保留多个实体id?
P.S. 我知道正确的方法是让这个函数采用参数来指定实体 ID 的数量并发出请求 return ids,但我想了解我们如何同步多次调用任何 returning promise 的函数。
首先,getReservedEntityId()
的实现需要正确使用promises。我建议通读 how promises work。特别是,重要的是要了解当您的函数执行异步任务时,您需要 return 一个承诺,该承诺将根据异步任务的结果解决或拒绝。
function getReservedEntityId(collectionName) {
if (haveCachedIds) {
return Promise.resolve(cachedId);
} else {
return new Promise((resolve, reject) => {
// Make the AJAX call and call resolve(newId) in the success callback
// or call reject(errCode) in the failure callback.
// The arguments newId and errCode can be any values you like and are
// the values that get passed to the next link in the promise chain
// i.e. the values passed to then() or catch()
});
}
}
考虑到这一点,有两种推荐的方法可以使调用同步:
1) 利用承诺链
getReservedEntityId(collectionName)
.then((id) => {
// Probably want to do something with `id` first...
return getReservedEntityId(collectionName);
})
.then( ... )
.then( ... );
当然,如果您要将相同的函数传递给每个 .then()
调用,您也可以将其声明为常规函数,以免重复。
2) 使用async/await
这是 ES2017 的一项新功能,仍未得到广泛支持。截至撰写本文时,Node.js 支持带有 --harmony
标志的 async/await,但 most browsers do not。也就是说,async/await 正是为了这个目的,将函数 returning 承诺视为同步。如果您想现在开始在您的代码中使用 async/await,通常的做法是使用 JavaScript 转译器,它将您的 future-ready JavaScript 转译为所有主要支持的代码浏览器。
这就是您的使用方式 async/await:
(async function someAsyncFunction {
const id1 = await getReservedEntityId(collectionName);
const id2 = await getReservedEntityId(collectionName);
const id3 = await getReservedEntityId(collectionName);
.
.
.
})();
语法比承诺链更好、更易读,因为它正是为此目的而设计的。请注意,我在这里创建了函数 self-invoking 以便它可以匹配您的行为,而无需进行额外的函数调用。但是您可以像使用 return 承诺的任何其他函数一样使用和调用用 async function
定义的函数。
@fvgs 你的回答也是正确的。但这是完整的解决方案,我面临的挑战是维护响应每个 getReservedEntityId 调用的 reserveIds 列表。
getEntityIds: function (entity, count) {
if (!count || count == 1)
return Utils.getReservedEntityId(entity);
var promise = new Promise(function(resolve, reject) {
var result = [];
var chain = Utils.getReservedEntityId(entity);
var callBack = function CB (result, newId) {
result.push(newId);
if (result.length == count)
resolve(result);
else
return Utils.getReservedEntityId(entity);
}.bind(null, result);
for (var i=1; i <= count; i++) {
chain.then(callBack);
}
chain.catch(reject);
});
return promise;
}
例如,如果我已经有任何缓存的实体 ID,我有 Promise.resolve() 函数,否则它会调用 ajax 来保留实体 ID,然后调用 Promise.resolve() new实体编号
function getReservedEntityId(collectionName) {
//if (!haveCachedIds) {
//make ajax call to reserve new ids
Promise.resolve(newId);
}
return Promise.resolve(cachedId);
};
如何同步调用多次来保留多个实体id?
P.S. 我知道正确的方法是让这个函数采用参数来指定实体 ID 的数量并发出请求 return ids,但我想了解我们如何同步多次调用任何 returning promise 的函数。
首先,getReservedEntityId()
的实现需要正确使用promises。我建议通读 how promises work。特别是,重要的是要了解当您的函数执行异步任务时,您需要 return 一个承诺,该承诺将根据异步任务的结果解决或拒绝。
function getReservedEntityId(collectionName) {
if (haveCachedIds) {
return Promise.resolve(cachedId);
} else {
return new Promise((resolve, reject) => {
// Make the AJAX call and call resolve(newId) in the success callback
// or call reject(errCode) in the failure callback.
// The arguments newId and errCode can be any values you like and are
// the values that get passed to the next link in the promise chain
// i.e. the values passed to then() or catch()
});
}
}
考虑到这一点,有两种推荐的方法可以使调用同步:
1) 利用承诺链
getReservedEntityId(collectionName)
.then((id) => {
// Probably want to do something with `id` first...
return getReservedEntityId(collectionName);
})
.then( ... )
.then( ... );
当然,如果您要将相同的函数传递给每个 .then()
调用,您也可以将其声明为常规函数,以免重复。
2) 使用async/await
这是 ES2017 的一项新功能,仍未得到广泛支持。截至撰写本文时,Node.js 支持带有 --harmony
标志的 async/await,但 most browsers do not。也就是说,async/await 正是为了这个目的,将函数 returning 承诺视为同步。如果您想现在开始在您的代码中使用 async/await,通常的做法是使用 JavaScript 转译器,它将您的 future-ready JavaScript 转译为所有主要支持的代码浏览器。
这就是您的使用方式 async/await:
(async function someAsyncFunction {
const id1 = await getReservedEntityId(collectionName);
const id2 = await getReservedEntityId(collectionName);
const id3 = await getReservedEntityId(collectionName);
.
.
.
})();
语法比承诺链更好、更易读,因为它正是为此目的而设计的。请注意,我在这里创建了函数 self-invoking 以便它可以匹配您的行为,而无需进行额外的函数调用。但是您可以像使用 return 承诺的任何其他函数一样使用和调用用 async function
定义的函数。
@fvgs 你的回答也是正确的。但这是完整的解决方案,我面临的挑战是维护响应每个 getReservedEntityId 调用的 reserveIds 列表。
getEntityIds: function (entity, count) {
if (!count || count == 1)
return Utils.getReservedEntityId(entity);
var promise = new Promise(function(resolve, reject) {
var result = [];
var chain = Utils.getReservedEntityId(entity);
var callBack = function CB (result, newId) {
result.push(newId);
if (result.length == count)
resolve(result);
else
return Utils.getReservedEntityId(entity);
}.bind(null, result);
for (var i=1; i <= count; i++) {
chain.then(callBack);
}
chain.catch(reject);
});
return promise;
}