国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

翻譯:Taming the asynchronous beast with ES7

Eastboat / 437人閱讀

摘要:讓我們使用它從數組中返回一個值數組在中,我們可以這樣做,這是一種更簡單的方法最重要的部分是創建數組,該數組立即調用所有的我們在主函數中等待這些。所以在我們真正等待完成之前,主函數就退出了。

原文:https://pouchdb.com/2015/03/0...

PouchDB最棘手的方面之一是它的API是異步的。在Stack Overflow、Github和IRC上,我看到了不少困惑的問題,而且這些問題通常是由對callbacks和promises的誤解造成的。

我們真的無能為力。PouchDB是對IndexedDB, WebSQL, LevelDB (in Node), and CouchDB (via Ajax)的抽象。所有這些API都是異步的;因此PouchDB必須是異步的。

然而,當我想到優雅的數據庫API時,我仍然對LocalStorage的簡單性感到震驚:
    if (!localStorage.foo) {
      localStorage.foo = "bar";
    };
    console.log(localStorage.foo);
要使用LocalStorage,您只需將它當作一個神奇的javascript對象來保存數據。它使用的同步工具集與使用JavaScript本身時已經習慣的工具集相同。

對于LocalStorage的所有錯誤(https://www.html5rocks.com/en/tutorials/offline/quota-research/),這個API的人機工程學在很大程度上解釋了它的持續流行。人們一直在使用LocalStorage,因為它很簡單,而且工作正常。
Promises aren"t a panacea
對于PouchDB,我們可以嘗試通過promises來減輕異步API的復雜性,這當然有助于我們擺脫pyramid of doom。

然而,promisey代碼仍然很難閱讀,因為promisey基本上是語言原語(如try、catch和return)的bolt-on替換:
    var db = new PouchDB("mydb");
    db.post({}).then(function (result) { // post a new doc
      return db.get(result.id);          // fetch the doc
    }).then(function (doc) {
      console.log(doc);                  // log the doc
    }).catch(function (err) {
      console.log(err);                  // log any errors
    });
作為JavaScript開發人員,我們現在有兩個并行系統——sync and async——我們必須直截了當地記住這兩個系統。當我們的控制流變得更復雜時,情況會變得更糟,我們需要使用promise.all()和promise.resolve()等API。或者我們只是選擇了眾多幫助程序庫中的一個,并祈禱我們能夠理解文檔。

直到最近,這是我們所能期望的最好的。但所有這些都隨ES7而改變。
Enter ES7
如果我告訴你,有了ES7,你可以把上面的代碼改寫成這樣:
let db = new PouchDB("mydb");
try {
  let result = await db.post({});
  let doc = await db.get(result.id);
  console.log(doc);
} catch (err) {
  console.log(err);
}

如果我告訴你,多虧了Babel.js和Regenerator這樣的工具,你現在可以將其發展到ES5并在瀏覽器中運行它了?
女士們先生們,請大家鼓掌,直到博文結束。
首先,讓我們看看ES7是如何完成這一驚人的壯舉的。
Async functions
ES7為我們提供了一種新的函數,async函數。在async函數內部,我們有一個新的關鍵字wait,用于“wait for”一個promise:
    async function myFunction() {
      let result = await somethingThatReturnsAPromise();
      console.log(result); // cool, we have a result
    }
如果promise resolves,我們可以在下一行立即與之交互。如果它拒絕了,那么就會拋出一個錯誤。所以,try/catch實際上再次有效!
    async function myFunction() {
      try {
        await somethingThatReturnsAPromise();
      } catch (err) { 
        console.log(err); // oh noes, we got an error
      }
    }
這允許我們編寫表面上看起來是同步的,但實際上是異步的代碼。API返回一個promise 而不是阻塞事件循環這一事實只是一個實現細節。
還記得你什么時候可以只使用"return"和"try/catch"嗎?

最好的一點是,我們今天可以把它和任何一個可以返回promises 的庫一起使用。PouchDB就是這樣一個庫,所以讓我們用它來測試我們的理論。
Managing errors and return values
首先,考慮一下pouchdb中的一個常見習慣用法:如果文檔存在,我們希望按_id獲取一個文檔,如果不存在,則返回一個新文檔。
有了promises,你就必須寫下這樣的東西:
    db.get("docid").catch(function (err) {
      if (err.name === "not_found") {
        return {}; // new doc
      }
      throw err; // some error other than 404
    }).then(function (doc) {
      console.log(doc);
    })
對于異步函數,這將變成:
    let doc;
    try {
      doc = await db.get("docid");
    } catch (err) {
      if (err.name === "not_found") {
        doc = {};
      } else {
        throw err; // some error other than 404
      }
    }
    console.log(doc);

    可讀性更高!如果db.get()直接返回一個文檔而不是一個promise,那么這幾乎是我們編寫的代碼。唯一的區別是,當我們調用任何promise-returning函數時,必須添加wait關鍵字。
Potential gotchas
我在玩這個的時候遇到了一些微妙的問題,所以很高興能意識到它們。
首先,當您等待某件事情時,您需要在一個async函數中。因此,如果您的代碼嚴重依賴PouchDB,您可能會發現您編寫了許多async函數,但很少有常規函數。
另一個更陰險的問題是,您必須小心地將代碼包裝在try/catch中,否則promise可能會被拒絕,在這種情況下,錯誤會被默默地吞沒。(!)
我的建議是確保您的async函數完全被try/catch包圍,至少在頂層:
async function createNewDoc() {
  let response = await db.post({}); // post a new doc
  return await db.get(response.id); // find by id
}

async function printDoc() {
  try {
    let doc = await createNewDoc();
    console.log(doc);
  } catch (err) {
    console.log(err);
  }
}
Loops
當涉及到迭代時,Async 函數會變得非常令人印象深刻。例如,假設我們希望將一些文檔按順序插入到數據庫中。也就是說,我們希望這些promises一個接一個地執行,而不是同時執行。
使用標準的ES6承諾,我們必須滾動自己的promise鏈:
    var promise = Promise.resolve();
    var docs = [{}, {}, {}];
    
    docs.forEach(function (doc) {
      promise = promise.then(function () {
        return db.post(doc);
      });
    });
    
    promise.then(function () {
      // now all our docs have been saved
    });
這是可行的,但確實很難看。這也很容易出錯,因為如果您不小心做了:
    docs.forEach(function (doc) {
      promise = promise.then(db.post(doc));
    });

然后promises實際上會同時執行,這可能會導致意想不到的結果。
但是,使用ES7,我們可以使用常規for循環:
    let docs = [{}, {}, {}];
    
    for (let i = 0; i < docs.length; i++) {
      let doc = docs[i];
      await db.post(doc);
    }
這個(非常簡潔的)代碼與promise鏈的作用是一樣的!我們可以通過以下方式使其更短:
    let docs = [{}, {}, {}];
    
    for (let doc of docs) {
      await db.post(doc);
    }
注意,這里不能使用foreach()循環,如果你天真地寫:
    let docs = [{}, {}, {}];
    
    // WARNING: this won"t work
    docs.forEach(function (doc) {
      await db.post(doc);
    });
然后Babel.js將失敗,并出現一些不透明的錯誤:
    Error : /../script.js: Unexpected token (38:23)
    > 38 |     await db.post(doc);
 |           ^

這是因為在正常函數中不能使用wait。您必須使用async函數。
但是,如果您嘗試使用async函數,那么您將得到一個更微妙的錯誤:

    let docs = [{}, {}, {}];
    
    // WARNING: this won"t work
    docs.forEach(async function (doc, i) {
      await db.post(doc);
      console.log(i);
    });
    console.log("main loop done");
這將編譯,但問題是這將打印出來:
    main loop done
    0
    1
    2

發生的是,主函數提前退出,因為await實際上在子函數中。此外,這將同時執行每一個promise,這不是我們的預期。

教訓是:在async函數中有任何函數時要小心。wait只會暫停它的父函數,所以檢查它是否在做你認為它在做的事情。
Concurrent loops
但是,如果我們確實希望同時執行多個promises,那么使用ES7很容易實現這一點。
回想一下,有了ES6 promises,我們就有了promise.all()。讓我們使用它從promises數組中返回一個值數組:        
    var docs = [{}, {}, {}];
    
    return Promise.all(docs.map(function (doc) {
      return db.post(doc);
    })).then(function (results) {
      console.log(results);
    });
在ES7中,我們可以這樣做,這是一種更簡單的方法:
    let docs = [{}, {}, {}];
    let promises = docs.map((doc) => db.post(doc));
    
    let results = [];
    for (let promise of promises) {
      results.push(await promise);
    }
    console.log(results);

最重要的部分是1)創建promises數組,該數組立即調用所有的promises;2)我們在主函數中等待這些promises。如果我們嘗試使用Array.prototype.map,那么它將無法工作:
    let docs = [{}, {}, {}];
    let promises = docs.map((doc) => db.post(doc));
    
    // WARNING: this doesn"t work
    let results = promises.map(async function(promise) {
      return await promise;
    });
    
    // This will just be a list of promises :(
    console.log(results);

不起作用的原因是我們在等待子函數的內部,而不是主函數。所以在我們真正等待完成之前,主函數就退出了。
如果您不介意使用promise.all,也可以使用它來整理代碼:
    
    let docs = [{}, {}, {}];
    let promises = docs.map((doc) => db.post(doc));
    
    let results = await Promise.all(promises);
    console.log(results);

如果我們使用數組壓縮,這看起來可能會更好。然而,規范還不是最終的,所以目前Regenerator不支持它。
Caveats
ES7仍然非常前沿。Node.js 或 io.js都不支持Async函數,您必須設置一些實驗標志,甚至讓babel考慮它。正式來說,async/await規范(https://github.com/tc39/ecmascript-asyncawait#status-of-this-proposal)仍處于“建議”階段。

另外,為了在ES5瀏覽器中工作,您還需要在您的開發代碼中包含Regenerator運行時和ES6 shims。對我來說,這加起來大約60kb,縮小和gzip。對于許多開發人員來說,這實在是太多了。

然而,所有這些新工具都非常有趣,它們描繪了異步庫在陽光明媚的ES7未來的美好圖景。


所以,如果你想自己玩,我已經建立了一個小的演示庫(https://github.com/nolanlawson/async-functions-in-pouchdb)。要開始,只需檢查代碼,運行npm安裝和npm運行build,就可以了。關于ES7的更多信息,請看JafarHusain的演講。
Conclusion
異步函數是ES7中的一個新概念。它們將我們丟失的returns和try/catches返回給我們,并獎勵我們已經從使用新的IDIOM編寫同步代碼中獲得的知識,這些IDIOM看起來很像舊的IDIOM,但性能更高。

最重要的是,async函數使得像PouchDB這樣的API更容易使用。因此,希望這將減少用戶錯誤和混淆,以及更優雅和可讀的代碼。

誰知道呢,也許人們最終會放棄LocalStorage,選擇更現代的客戶端數據庫。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105372.html

相關文章

  • JavaScript異步編程解決方案筆記

    摘要:異步編程解決方案筆記最近讀了樸靈老師的深入淺出中異步編程一章,并參考了一些有趣的文章。另外回調函數中的也失去了意義,這會使我們的程序必須依賴于副作用。 JavaScript 異步編程解決方案筆記 最近讀了樸靈老師的《深入淺出NodeJS》中《異步編程》一章,并參考了一些有趣的文章。在此做個筆記,記錄并鞏固學到的知識。 JavaScript異步編程的兩個核心難點 異步I/O、事件驅動使得...

    dmlllll 評論0 收藏0
  • Javascript的模塊管理 CMD AMD ES7

    摘要:一一開始是垃圾,但隨著時代的發展業務的進步,變得越來越重要,但涉及之初就是用來打雜的,有缺陷如下簡單翻譯下沒有模塊系統沒有標準庫沒有文件沒有系統沒有標準接口,用來做服務器或者數據庫沒有依賴包管理系統。 一 Commonjs 一開始js是垃圾,但隨著時代的發展、業務的進步,js變得越來越重要,但js涉及之初就是用來打雜的,有缺陷如下: JavaScript has no module ...

    darryrzhong 評論0 收藏0
  • 通過ES6 Generator函數實現異步流程

    摘要:換句話說,我們很好的對代碼的功能關注點進行了分離通過將使用消費值得地方函數中的邏輯和通過異步流程來獲取值迭代器的方法進行了有效的分離。但是現在我們通過來管理代碼的異步流程部分,我們解決了回調函數所帶來的反轉控制等問題。 本文翻譯自 Going Async With ES6 Generators 由于個人能力知識有限,翻譯過程中難免有紕漏和錯誤,還望指正Issue ES6 Gener...

    劉厚水 評論0 收藏0
  • ES6中的異步編程:Generators函數+Promise:最強大的異步處理方式

    摘要:更好的異步編程上面的方法可以適用于那些比較簡單的異步工作流程。小結的組合目前是最強大,也是最優雅的異步流程管理編程方式。 訪問原文地址 generators主要作用就是提供了一種,單線程的,很像同步方法的編程風格,方便你把異步實現的那些細節藏在別處。這讓我們可以用一種很自然的方式書寫我們代碼中的流程和狀態邏輯,不再需要去遵循那些奇怪的異步編程風格。 換句話說,通過將我們generato...

    Taonce 評論0 收藏0
  • 2017-07-10 前端日報

    摘要:前端日報精選入門指南入口,輸出,加載器和插件中數據類型轉換讓我印象深刻的面試題大話大前端時代一與的組件化庖丁解牛一發布中文第期手把手教你用管理狀態上個快速編程技巧眾成翻譯中執行順序組件解耦之道眾成翻譯組件模型啟示錄有個梨作 2017-07-10 前端日報 精選 Webpack入門指南: 入口,輸出,加載器和插件JavaScript中數據類型轉換讓我印象深刻的javascript面試題大...

    Heier 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<