簡體   English   中英

如何在同步方法中使用異步方法

[英]How to use asynchronous method in a synchronous method

我用網絡技術開發了一個將數據存儲在LocalStorage中的游戲。 LocalStorage是同步的。要設置和獲取localstorage的值,請按照以下步驟操作:

//在localstorage中設置值

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

//從localstorage獲取值

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

本地存儲限制為5MB。 發揮一定程度后,本地存儲完全填滿。 我需要在客戶端存儲一個大區域。

我的第一個問題是“解決此問題的最佳方法什么?”

為了解決上述問題,我找到了LargeLocalStorage。它可以異步工作。

//在LargeLocalStorage中設置值

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

//從LargeLocalStorage獲取值

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

有沒有什么方法可以使這些方法同步,因為我的所有代碼都是根據同步本地存儲進行的。 根據異步LargeLocalStorage更改整個邏輯將花費大量時間。

我目前正在嘗試將localstorage的setItem和getItem方法重寫為:

localStorage.__proto__.getItem = function(key) {

var returnVal;

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

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

由於異步行為,上面的重寫方法返回未定義的值。

請幫助我使用上述方法使價值同步。

提前致謝。

好的,LocalStorage很不錯,但是如果您想存儲很多數據,我建議您看一下PouchDB ,它是NoSQL數據庫CouchDB的JavaScript實現。

Pouchdb使用IndexedDB作為其存儲機制。 因此,PouchDB在瀏覽器中運行,從而提供了速度。

我認為這對您的情況非常有幫助:)。

如果您有時間,請看一下我編寫的這段代碼:

數據庫類

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;
      }
    }

  })();

做一些動作

  //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>

我認為PouchDB是一個非常好的東西,如果您有時間,可以隨意進行測試:)

有什么辦法可以使這些方法同步

不能。異步方法是異步的,因為它們很好,是異步的。 您無法做出明天(或從現在起100毫秒)要發生的事情,而是立即發生。

您真正想要的是一種以看起來像同步代碼的方式編寫異步代碼的方法。 這將更具可讀性,並且在您的情況下,這將使代碼修改更加容易。

我們希望以某種方式能夠寫

A() . then(B);

A();
B();

並且具有相同的意思:等待A完成之后再執行B。如果涉及變量或結果,那么我們希望能夠編寫

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

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

異步功能

原來有一種方法可以做到這一點: 異步功能 並非在所有環境中都可以使用此功能,但是很容易找到訪問它的方法。 要使用異步函數,我將關鍵字async放在function前面,然后使用特殊關鍵字await 因此,上面的代碼變為:

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

為了使它起作用,請使用Babel轉換代碼,選擇啟用異步功能的選項。 Babel會將您的代碼轉換為ES5,這是所有瀏覽器都知道如何解釋的JavaScript。

上面的代碼實際上將返回一個承諾,您可以將其掛起, then使用,或在另一個異步函數中使用:

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

在您的特定情況下:

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

發電機

您可能想知道另一種方法。 它使用“生成器”,這是ES6中的一種特殊類型的函數,可以“返回”一個值,但保持其狀態,並且可以在兩次之間執行操作之后再次調用並返回更多值。 生成器是這樣寫的,在函數名稱后帶有*

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

以特殊方式調用此函數。 首先,將其稱為foo()來創建稱為iterator的東西,然后使用iterator的next方法獲取下一個值。 (還有其他方法可以檢索值的序列,在此不再贅述。)

這些生成器可用於編寫所需的“異步但看起來同步”的代碼,如下所示:

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

該代碼看起來與async函數非常相似,但是使用yield代替了await

但是在這種情況下,與上述異步函數不同,我們需要某人或某物來請求第一個值,然后等待yield返回的promise解析,然后再請求第二個值,依此類推。 這樣做的代碼並不長,但是有點復雜。 有許多庫和實用程序可以做到這一點。 例如,一個著名的公司叫做co 使用co ,您可以編寫與我先前顯示的異步功能相同的代碼,如下所示:

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

采用這種方法的一個原因是,生成器在ES6中是標准的,並且比異步功能更為廣泛地使用,異步功能正被ES7考慮。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM