asynchronous - What is a canonical safe way of async lazy initialization in javascript? - Stack Overflow

I have this sort of lazy initialization code in my program: let user = null;let getUser

I have this sort of lazy initialization code in my program:

let user = null;        
let getUser = async () => {
  if(!user) {
    user = await getUserSomehow();
  }
  return user;
};

I understand that it is not safe, due to a possible race condition if I have the next code:

// one place of the program
let u1 = await getUser();
...
// another place of the program running during getUserSomehow() for u1 still hasn't finished
let u2 = await getUser();

getUserSomehow() will be called two times instead of one.

How to avoid this situation?

I have this sort of lazy initialization code in my program:

let user = null;        
let getUser = async () => {
  if(!user) {
    user = await getUserSomehow();
  }
  return user;
};

I understand that it is not safe, due to a possible race condition if I have the next code:

// one place of the program
let u1 = await getUser();
...
// another place of the program running during getUserSomehow() for u1 still hasn't finished
let u2 = await getUser();

getUserSomehow() will be called two times instead of one.

How to avoid this situation?

Share Improve this question edited Nov 11, 2019 at 9:44 Arsenii Fomin asked Nov 11, 2019 at 6:10 Arsenii FominArsenii Fomin 3,3564 gold badges25 silver badges48 bronze badges 2
  • 1 Just drop the await. – Bergi Commented Nov 11, 2019 at 7:43
  • @Bergi your ment is so short that at first glance it looks stupid (like you are advising to get rid of async code). However, if it's not planned to use "user" variable directly anywhere, you are pletely right. – Arsenii Fomin Commented Nov 11, 2019 at 9:47
Add a ment  | 

1 Answer 1

Reset to default 10

When called for the first time, assign a Promise instead, and on further calls, return that Promise:

let userProm = null;
let getUser = () => {
  if (!userProm) {
    userProm = getUserSomehow();
  }
  return userProm;
};

Even better, scope userProm only inside getUser, to be safer and clear:

const getUser = (() => {
  let userProm = null;
  return () => {
    if (!userProm) {
      userProm = getUserSomehow();
    }
    return userProm;
  };
})();

const getUserSomehow = () => {
  console.log('getting user');
  return Promise.resolve('data');
};

const getUser = (() => {
  let userProm = null;
  return () => {
    if (!userProm) {
      userProm = getUserSomehow();
    }
    return userProm;
  };
})();

(async () => {
  const userProm1 = getUser();
  const userProm2 = getUser();
  Promise.all([userProm1, userProm2]).then(() => {
    console.log('All done');
  });
})();

Your existing code happens to be safe, because the assignment to user will occur before the first call of getUser finishes:

const getUserSomehow = () => {
  console.log('Getting user');
  return Promise.resolve('data');
};

let user = null;
let getUser = async() => {
  if (!user) {
    user = await getUserSomehow();
  }
  return user;
};

(async () => {
  let u1 = await getUser();
  let u2 = await getUser();
  console.log('Done');
})();

But it wouldn't be if the Promises were initialized in parallel, before one of them was awaited to pletion first:

const getUserSomehow = () => {
  console.log('Getting user');
  return Promise.resolve('data');
};

let user = null;
let getUser = async() => {
  if (!user) {
    user = await getUserSomehow();
  }
  return user;
};

(async() => {
  let u1Prom = getUser();
  let u2Prom = getUser();
  await Promise.all([u1Prom, u2Prom]);
  console.log('Done');
})();

As shown above, assigning the Promise to the persistent variable (instead of awaiting the value inside getUser) fixes this.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744135492a4560039.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信