解释如何使用IndexedDB在此JavaScript代码中使用生成器?

dum*_*ter 7 javascript generator indexeddb javascript-1.8

同时通过IndexedDB的美妙的世界我的方式,我碰到像代码这个来自Mozilla的测试套件:

/**
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

var testGenerator = testSteps();

function testSteps()
{
  const IDBObjectStore = Components.interfaces.nsIIDBObjectStore;
  const name = this.window ? window.location.pathname : "Splendid Test";
  const description = "My Test Database";

  var data = [
    { name: "inline key; key generator",
      autoIncrement: true,
      storedObject: {name: "Lincoln"},
      keyName: "id",
      keyValue: undefined,
    },
    { name: "inline key; no key generator",
      autoIncrement: false,
      storedObject: {id: 1, name: "Lincoln"},
      keyName: "id",
      keyValue: undefined,
    },
    { name: "out of line key; key generator",
      autoIncrement: true,
      storedObject: {name: "Lincoln"},
      keyName: undefined,
      keyValue: undefined,
    },
    { name: "out of line key; no key generator",
      autoIncrement: false,
      storedObject: {name: "Lincoln"},
      keyName: null,
      keyValue: 1,
    }
  ];

  for (let i = 0; i < data.length; i++) {
    let test = data[i];

    let request = mozIndexedDB.open(name, i+1, description);
    request.onerror = errorHandler;
    request.onupgradeneeded = grabEventAndContinueHandler;
    let event = yield;

    let db = event.target.result;

    let objectStore = db.createObjectStore(test.name,
                                           { keyPath: test.keyName,
                                             autoIncrement: test.autoIncrement });

    request = objectStore.add(test.storedObject, test.keyValue);
    request.onerror = errorHandler;
    request.onsuccess = grabEventAndContinueHandler;
    event = yield;

    let id = event.target.result;
    request = objectStore.get(id);
    request.onerror = errorHandler;
    request.onsuccess = grabEventAndContinueHandler;
    event = yield;

    // Sanity check!
    is(test.storedObject.name, event.target.result.name,
                  "The correct object was stored.");

    request = objectStore.delete(id);
    request.onerror = errorHandler;
    request.onsuccess = grabEventAndContinueHandler;
    event = yield;

    // Make sure it was removed.
    request = objectStore.get(id);
    request.onerror = errorHandler;
    request.onsuccess = grabEventAndContinueHandler;
    event = yield;

    ok(event.target.result === undefined, "Object was deleted");
    db.close();
  }

  finishTest();
  yield;
}
Run Code Online (Sandbox Code Playgroud)

他们的其他测试是以类似的方式编写的,而不是您使用IndexedDB看到的典型的"厄运金字塔"样式,因为异步回调被堆叠在一起(当然,除了Firefox之外,生成器还没有被广泛支持).

因此,来自Mozilla的这段代码对我来说有点吸引力和吸引力,因为它看起来很干净,但我不完全确定yield在这种情况下做了什么.任何人都可以帮我理解这个吗?

Aad*_*hah 5

这是一段精彩的代码,利用了Firefox公开的JavaScript 1.7强大的新功能,而且只有Firefox和Chrome支持IndexedDB,我认为这是一个很好的权衡.

代码的第一行从函数创建生成器testSteps并将其分配给变量testGenerator.我们使用生成器的原因是因为IndexedDB是一个纯粹的异步API; 和异步编程和嵌套回调是一个痛苦.使用生成器允许您编写看起来同步的异步代码,从而减轻了这种痛苦.

注意:如果您想知道如何利用生成器的强大功能使异步代码同步阅读以下文章.

要解释生成器如何使异步编程变得可用,请考虑以下代码:

var name = "Test";
var version = 1.0;
var description = "Test database.";

var request = mozIndexedDB.open(name, version, description);

request.onupgradeneeded = function (event) {
    var db = event.target.result;

    var objectStore = db.createObjectStore("Thing", {
        keyPath: "id",
        autoIncrement: true
    });

    var object = {
        attributeA: 1,
        attributeB: 2,
        attributeC: 3            
    };

    var request = objectStore.add(object, "uniqueID");

    request.onsuccess = function (event) {
        var id = event.target.result;
        if (id === "uniqueID") alert("Object stored.");
        db.close();
    };
};
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我们请求了一个名为的数据库Test.我们要求提供数据库版本1.0.由于它不存在,onupgradeneeded因此触发了事件处理程序.获得数据库后,我们在其上创建了一个对象存储,向对象存储添加了一个对象,保存后我们关闭了数据库.

上面代码的问题是我们正在请求数据库并异步执行与之相关的其他操作.随着越来越多的嵌套回调被采用,这可能使代码难以维护.

为了解决这个问题,我们使用生成器如下:

var gen = (function (name, version, description) {
    var request = mozIndexedDB.open(name, version, description);

    request.onupgradeneeded = grabEventAndContinueHandler;

    var event = yield;

    var db = event.target.result;

    var objectStore = db.createObjectStore("Thing", {
        keyPath: "id",
        autoIncrement: true
    });

    var object = {
        attributeA: 1,
        attributeB: 2,
        attributeC: 3
    };

    request = objectStore.add(object, "uniqueID");

    request.onsuccess = grabEventAndContinueHandler;

    event = yield;

    var id = event.target.result;

    if (id === "uniqueID") alert("Object stored.");

    db.close();
}("Test", 1.0, "Test database."));
Run Code Online (Sandbox Code Playgroud)

grabEventAndContinueHandler函数在生成器之后定义如下:

function grabEventAndContinueHandler(event) {
    gen.send(event);
}
Run Code Online (Sandbox Code Playgroud)

生成器启动如下:

gen.next();
Run Code Online (Sandbox Code Playgroud)

启动生成器后,将请求打开与给定数据库的连接.然后grabEventAndContinueHandler作为事件处理程序附加到onupgradeneeded事件.最后,我们使用关键字生成或暂停生成器yield.

gen.sendgrabEventAndContinueHandler函数调用方法时,生成器自动恢复.此函数只需调用一个参数event并将其发送到生成器.当生成器恢复时,发送的值存储在一个名为的变量中event.

回顾一下,魔术发生在这里:

// resume the generator when the event handler is called
// and send the onsuccess event to the generator
request.onsuccess = grabEventAndContinueHandler;

// pause the generator using the yield keyword
// and save the onsuccess event sent by the handler
var event = yield;
Run Code Online (Sandbox Code Playgroud)

上面的代码使得编写异步代码成为可能,就好像它是同步的一样.要了解有关生成器的更多信息,请阅读以下MDN文章.希望这可以帮助.