如何将 Promise.resolve 应用于需要原子化的代码
How to apply Promise.resolve for code that needs to be atomic
我在合作伙伴管理器上工作,一些代码需要是原子的,因为当前存在竞争条件并且当 2 个客户端同时调用相同资源时无法工作。 retrievePartners 方法 returns partners 并且该方法应该是原子的。基本上合作伙伴是有限的资源,提供机制应该一次只处理一个客户(要求合作伙伴)。
有人告诉我下面的代码适用于原子操作,因为 javascript 是本机的原子操作。
let processingQueue = Promise.resolve();
function doStuffExclusively() {
processingQueue = processingQueue.then(() => {
return fetch('http://localhost', {method: 'PUT', body: ...});
}).catch(function(e){
throw e;
});
return processingQueue;
}
doStuffExclusively()
doStuffExclusively()
doStuffExclusively()
但是这段代码是基本的,我的代码有一些 await 调用另一个 await ,等等。我想为下面的代码应用该机制,但真的不知道该怎么做,我试了几次但没有成功。无法在 then 语句中等待工作。
我也很困惑上面的代码 return 在 processingQueue 的 then 部分是真的。但是在我的例子中,我 return 一个数组,或者抛出一个错误信息。我应该 return 让它像上面那样工作吗?
这是我想像上面的代码一样使其成为原子的函数。我试图将此函数中的所有内容放在 return 语句之前的 then 部分中,但没有成功,因为
export class Workout {
constructor (config) {
this.instructorPeer = new jet.Peer(config)
this.instructorPeer.connect()
}
async createSession (partnerInfo) {
const partners = { chrome: [], firefox: [], safari: [], ie: [] }
const appropriatePartners = await this.retrievePartners(partnerInfo)
Object.keys(appropriatePartners).forEach(key => {
appropriatePartners[key].forEach(partner => {
const newPartner = new Partner(this.instructorPeer, partner.id)
partners[key].push(newPartner)
})
})
return new Session(partners)
}
async retrievePartners (capabilities) {
const appropriatePartners = { chrome: [], firefox: [], safari: [], ie: [] }
const partners = await this.getAllPartners()
// first check if there is available appropriate Partners
Object.keys(capabilities.type).forEach(key => {
let typeNumber = parseInt(capabilities.type[key])
for (let i = 0; i < typeNumber; i++) {
partners.forEach((partner, i) => {
if (
key === partner.value.type &&
partner.value.isAvailable &&
appropriatePartners[key].length < typeNumber
) {
appropriatePartners[key].push(partner)
console.log(appropriatePartners[key].length)
}
})
if (appropriatePartners[key].length < typeNumber) {
throw new Error(
'Sorry there are no appropriate Partners for this session'
)
}
}
})
Object.keys(appropriatePartners).forEach(key => {
appropriatePartners[key].forEach(partner => {
this.instructorPeer.set('/partners/' + partner.id + '/states/', {
isAvailable: false
})
})
})
return appropriatePartners
}
async getAllPartners (capabilities) {
const partners = []
const paths = await this.instructorPeer.get({
path: { startsWith: '/partners/' }
})
paths.forEach((path, i) => {
if (path.fetchOnly) {
let obj = {}
obj.value = path.value
obj.id = path.path.split('/partners/')[1]
obj.value.isAvailable = paths[i + 1].value.isAvailable
partners.push(obj)
}
})
return partners
}
这是调用它的代码
async function startTest () {
const capabilities = {
type: {
chrome: 1
}
}
const workoutServerConfig = {
url: 'ws://localhost:8090'
}
const workout = createWorkout(workoutServerConfig)
const session = await workout.createSession(capabilities)
const session1 = await workout.createSession(capabilities)
这是我尝试过但没有成功的方法,会话未定义等等
let processingQueue = Promise.resolve()
export class Workout {
constructor (config) {
this.instructorPeer = new jet.Peer(config)
this.instructorPeer.connect()
this.processingQueue = Promise.resolve()
}
async createSession (partnerInfo) {
this.processingQueue = this.processingQueue.then(() => {
const partners = { chrome: [], firefox: [], safari: [], ie: [] }
const appropriatePartners = this.retrievePartners(partnerInfo)
Object.keys(appropriatePartners).forEach(key => {
appropriatePartners[key].forEach(partner => {
const newPartner = new Partner(this.instructorPeer, partner.id)
partners[key].push(newPartner)
})
})
return new Session(partners)
})
}
这是基于承诺的锁定,基于以下事实:
1) .then()
处理程序只会在锁定解决后被调用。
2) 一旦 .then()
处理程序开始执行,由于 JS 的执行模型,其他 JS 代码将不会执行。
您引用的方法的整体结构是正确的。
我在您的代码中看到的主要问题是 const appropriatePartners = this.retrievePartners(partnerInfo)
将评估为承诺,因为 retrievePartners
是异步的。你想要:
const appropriatePartners = await this.retrievePartners(partnerInfo)
.
这将导致您的锁的执行程序在 retrievePartners
调用上阻塞,而目前您只是获取一个承诺包装该调用的最终 return 值。
编辑:参见 jsfiddle 示例。
总之:
1) 使箭头函数处理锁定解析async
2) 确保它 await
是 this.retrievePartners
的 return 值,否则您将在 Promise 上操作,而不是解析值。
我在合作伙伴管理器上工作,一些代码需要是原子的,因为当前存在竞争条件并且当 2 个客户端同时调用相同资源时无法工作。 retrievePartners 方法 returns partners 并且该方法应该是原子的。基本上合作伙伴是有限的资源,提供机制应该一次只处理一个客户(要求合作伙伴)。
有人告诉我下面的代码适用于原子操作,因为 javascript 是本机的原子操作。
let processingQueue = Promise.resolve();
function doStuffExclusively() {
processingQueue = processingQueue.then(() => {
return fetch('http://localhost', {method: 'PUT', body: ...});
}).catch(function(e){
throw e;
});
return processingQueue;
}
doStuffExclusively()
doStuffExclusively()
doStuffExclusively()
但是这段代码是基本的,我的代码有一些 await 调用另一个 await ,等等。我想为下面的代码应用该机制,但真的不知道该怎么做,我试了几次但没有成功。无法在 then 语句中等待工作。
我也很困惑上面的代码 return 在 processingQueue 的 then 部分是真的。但是在我的例子中,我 return 一个数组,或者抛出一个错误信息。我应该 return 让它像上面那样工作吗?
这是我想像上面的代码一样使其成为原子的函数。我试图将此函数中的所有内容放在 return 语句之前的 then 部分中,但没有成功,因为
export class Workout {
constructor (config) {
this.instructorPeer = new jet.Peer(config)
this.instructorPeer.connect()
}
async createSession (partnerInfo) {
const partners = { chrome: [], firefox: [], safari: [], ie: [] }
const appropriatePartners = await this.retrievePartners(partnerInfo)
Object.keys(appropriatePartners).forEach(key => {
appropriatePartners[key].forEach(partner => {
const newPartner = new Partner(this.instructorPeer, partner.id)
partners[key].push(newPartner)
})
})
return new Session(partners)
}
async retrievePartners (capabilities) {
const appropriatePartners = { chrome: [], firefox: [], safari: [], ie: [] }
const partners = await this.getAllPartners()
// first check if there is available appropriate Partners
Object.keys(capabilities.type).forEach(key => {
let typeNumber = parseInt(capabilities.type[key])
for (let i = 0; i < typeNumber; i++) {
partners.forEach((partner, i) => {
if (
key === partner.value.type &&
partner.value.isAvailable &&
appropriatePartners[key].length < typeNumber
) {
appropriatePartners[key].push(partner)
console.log(appropriatePartners[key].length)
}
})
if (appropriatePartners[key].length < typeNumber) {
throw new Error(
'Sorry there are no appropriate Partners for this session'
)
}
}
})
Object.keys(appropriatePartners).forEach(key => {
appropriatePartners[key].forEach(partner => {
this.instructorPeer.set('/partners/' + partner.id + '/states/', {
isAvailable: false
})
})
})
return appropriatePartners
}
async getAllPartners (capabilities) {
const partners = []
const paths = await this.instructorPeer.get({
path: { startsWith: '/partners/' }
})
paths.forEach((path, i) => {
if (path.fetchOnly) {
let obj = {}
obj.value = path.value
obj.id = path.path.split('/partners/')[1]
obj.value.isAvailable = paths[i + 1].value.isAvailable
partners.push(obj)
}
})
return partners
}
这是调用它的代码
async function startTest () {
const capabilities = {
type: {
chrome: 1
}
}
const workoutServerConfig = {
url: 'ws://localhost:8090'
}
const workout = createWorkout(workoutServerConfig)
const session = await workout.createSession(capabilities)
const session1 = await workout.createSession(capabilities)
这是我尝试过但没有成功的方法,会话未定义等等
let processingQueue = Promise.resolve()
export class Workout {
constructor (config) {
this.instructorPeer = new jet.Peer(config)
this.instructorPeer.connect()
this.processingQueue = Promise.resolve()
}
async createSession (partnerInfo) {
this.processingQueue = this.processingQueue.then(() => {
const partners = { chrome: [], firefox: [], safari: [], ie: [] }
const appropriatePartners = this.retrievePartners(partnerInfo)
Object.keys(appropriatePartners).forEach(key => {
appropriatePartners[key].forEach(partner => {
const newPartner = new Partner(this.instructorPeer, partner.id)
partners[key].push(newPartner)
})
})
return new Session(partners)
})
}
这是基于承诺的锁定,基于以下事实:
1) .then()
处理程序只会在锁定解决后被调用。
2) 一旦 .then()
处理程序开始执行,由于 JS 的执行模型,其他 JS 代码将不会执行。
您引用的方法的整体结构是正确的。
我在您的代码中看到的主要问题是 const appropriatePartners = this.retrievePartners(partnerInfo)
将评估为承诺,因为 retrievePartners
是异步的。你想要:
const appropriatePartners = await this.retrievePartners(partnerInfo)
.
这将导致您的锁的执行程序在 retrievePartners
调用上阻塞,而目前您只是获取一个承诺包装该调用的最终 return 值。
编辑:参见 jsfiddle 示例。
总之:
1) 使箭头函数处理锁定解析async
2) 确保它 await
是 this.retrievePartners
的 return 值,否则您将在 Promise 上操作,而不是解析值。