How to use asynchronous method in a synchronous method

不问归期 提交于 2019-12-25 06:59:57

问题


I developed a game in web technology that store the data in LocalStorage. The LocalStorage works as synchronous.To set and get the values from localstorage as

// set the value in localstorage

localStorage.setItem('Key', "value");

// get the value from localstorage

var localValue = localStorage.getItem('Key');

There is 5MB limit in localstorage. After play the some level, localstorage filled completely. I need a large area for storage at client side.

My first question is that “What is the best way to solve this problem?”

To solve above problem,I find the LargeLocalStorage.It is worked as asynchronous.

// set the value in LargeLocalStorage

storage.setContents('docKey', "the contents...").then(function() {alert('doc created/updated');});

// get the value from LargeLocalStorage

storage.getContents('myDoc').then(function(content){//content is value for particular key});

Is there is any way that make these method synchronous because my all code is according to the synchronous localstorage. It will take a lot of time to change the whole logic according to the asynchronous LargeLocalStorage.

I am currently try to override the setItem and getItem method of localstorage as :

localStorage.__proto__.getItem = function(key) {

var returnVal;

storage.getContents(key).then(function(content) {
        returnVal = content;

    });
return returnVal;//it returns undefined
}

Above override method returns undefined value due to asynchronous behaviour.

Please help me to get value synchronous using above methods.

Thanks in advance.


回答1:


Ok, LocalStorage is quiet good, but if you want to store a lot of data, i suggest you to take a look about PouchDB, which is a JavaScript implementation of CouchDB, a NoSQL database.

Pouchdb use IndexedDB as its storage mechanism. So, PouchDB runs in the browser, which provides speed.

I think that can be really helpful in your case :).

If you have time take a look about this piece of code that i've made :

Database Class

var Database = (function(){

    var instance = undefined;

    function Database(){
      //Create new database Game
      this.db = new PouchDB('Game');

      //Listen for db changes, and fired show function
      this.db.changes({
        since: 'now',
        live: true
      }).on('change', this.show);

    }

    //Show function retrieve all docs, and add it to the html
    Database.prototype.show = function(){
      this.db
      .allDocs({include_docs: true, descending: true})
      .then(function(response){
        var data = response.rows;
        var preview = document.querySelector('.preview');
        while (preview.firstChild) {
            preview.removeChild(preview.firstChild);
        }
        data.forEach(function(elm){
          var p = document.createElement('p');
          p.innerHTML = elm.doc.title;
          preview.appendChild(p);
        });
      });
    }


    //Add a doc to our database
    Database.prototype.add = function(data){
      this.db
      .post(data)
      .then(function(response){
        console.log('Data added !');
      }).catch(function(err){
        console.log(err);
      });
    }

    //Clean our database
    Database.prototype.reset = function(){
      var db = this.db;
      //retrieve all docs
      db.allDocs({include_docs:true, descending: true})
        .then(function(response){
          var rows = response.rows;
          var docs = rows.map(function(elm){
            return elm.doc;
          });
          //Create promises array
          var promises = docs.map(function(elm){
            //Return promise remove
            return db.remove(elm._id, elm._rev);
          });
          //Resolve all promisein our array
          Promise.all(promises).then(function(data){
            console.log('Database Cleaned !');
          });
        });
    }

    return {
      get: function(){
        if (!instance){
          instance = new Database();
        }
        return instance;
      }
    }

  })();

Do some action

  //Create a database
  var DB = Database.get();

  function add(){
    var value = document.querySelector('#value').value;

    var obj = {
      title: value
    };
    //Add obj to our database
    DB.add(obj);
  }

  function reset(){
    //Reset our database
    DB.reset();
  }

HTML

<input type="text" name="name" id="value">
<button type="button" name="button" onclick="add()">add</button>
<button type="button" name="button" onclick="reset()">Destory database</button>
<div class="preview">
</div>

I think that PouchDB is a really good stuff, if you have time, fell free to test it :)




回答2:


Is there is any way that make these method synchronous

No. Asynchronous methods are asynchronous because they are well, asynchronous. You cannot make something that is going to happen tomorrow (or 100ms from now) instead happen now.

What you really want is a way to write asynchronous code in such a way that it sort of looks like synchronous code. That will be both more readable, and in your case, will make adapting your code easier.

We want to somehow be able to write

A() . then(B);

as

A();
B();

and have it mean the same thing: to wait for A to finish before executing B. If a variable or result is involved, then we want to be able to write

A() . then(function(a) { return B(a+1); })

as

var a = A();
B(a+1);

Async functions

It turns out there is a way to do this: async functions. This feature is by no means available in all environments, but it's easy enough to find ways to access it. To use an async function, I put the keyword async in front of the function, then use the special keyword await. So the code above becomes just:

async function foo() {
  var a = await A();
  await B(a+1);
}

To get this to work, transpile your code with Babel, selecting the options for enabling async functions. Babel will translate your code into ES5, the kind of JavaScript all browsers know how to interpret.

The above code will actually return a promise that you can either hang a then from, or use in another async function:

async function bar() {
  await foo();
}

In your specific case:

async function write(contents) {
  await storage.setContents('docKey', contents);
  alert('doc created/updated');
}

Generators

There is another approach you might like to know about. It uses "generators", which are a special type of function in ES6 which "return" a value, but maintain their state, and can be called again and return more values after doing stuff in between. Generators are written like this, with an * after the function name:

function* foo() {
  yield 1;
  yield 2;
}

This function is called in a special way. First, you call it as foo() to make a thing called an iterator, and then you use the next method of the iterator to get the next value. (There are also other ways to retrieve the sequence of values, which we won't go into here.)

These generators can be used to write the kind of "asynchronous-but-looks-synchronous" code you want, as follows:

function* foo() {
  var a = yield A();
  yield B(a+1);
}

The code looks quite similar to the async function, but with yield replacing await.

But in this case, unlike the async functions described above, we need someone or something to ask for the first value, then wait for the promise returned by yield to resolve, then ask for the second value, and so on. The code do do so is not long, but is a bit complex. There are many libraries and utilities which do exactly that. For instance, a well-known one is called co. With co, you can write code which behaves identically to the async function I showed earlier as follows:

var foo = co.wrap(function* foo() {
  var a = yield A();
  yield B(a+1);
});

One reason for adopting this approach would be that generators are standard in ES6 and more widely available than async functions, which are being considered for ES7.



来源:https://stackoverflow.com/questions/32010458/how-to-use-asynchronous-method-in-a-synchronous-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!