博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LocalStorage在Chrome里的实现
阅读量:762 次
发布时间:2019-03-23

本文共 3772 字,大约阅读时间需要 12 分钟。

前段时间我们在实现CanTK-Runtime时,也曾在V8基础上模拟过浏览器的LocaleStorage功能,其实现非常简单:每个domain的数据使用的单独文件存储,因为同一时间只有一个游戏运行,所以文件操作只是放到了后台线程执行。但是Chrome里的实现就非常复杂了,它主要包括四部分:

  • 0.根据IDL文件产生出来的代码,称为Binding代码(gen/blink/bindings/modules/v8/V8Storage.cpp)。这些代码是JS与C++之间的桥梁,JS调用C++时传递过来的参数是一个数组,它负责把参数拆解出来然后调用实际的函数,执行完成后把参数返回给JS。
static void setItemMethod(const v8::FunctionCallbackInfo
& info){ ExceptionState exceptionState(ExceptionState::ExecutionContext, "setItem", "Storage", info.Holder(), info.GetIsolate()); if (UNLIKELY(info.Length() < 2)) { setMinimumArityTypeError(exceptionState, 2, info.Length()); exceptionState.throwIfNeeded(); return; } Storage* impl = V8Storage::toImpl(info.Holder()); V8StringResource<> key; V8StringResource<> data; { key = info[0]; if (!key.prepare()) return; data = info[1]; if (!data.prepare()) return; } impl->setItem(key, data, exceptionState); if (exceptionState.hadException()) { exceptionState.throwIfNeeded(); return; }}
  • 1.与浏览器JS对接的模块(WebKit/Source/modules/storage)。Binding代码会调用到这里来,这里主要做些参数以及安全方面的检查,然后调用WebStorageArea的接口。
void StorageArea::setItem(const String& key, const String& value, ExceptionState& exceptionState, LocalFrame* frame){    if (!canAccessStorage(frame)) {        exceptionState.throwSecurityError("access is denied for this document.");        return;    }    WebStorageArea::Result result = WebStorageArea::ResultOK;    m_storageArea->setItem(key, value, frame->document()->url(), result);    if (result != WebStorageArea::ResultOK)        exceptionState.throwDOMException(QuotaExceededError, "Setting the value of '" + key + "' exceeded the quota.");}
  • 2.客户端代理(content/renderer/dom_storage/webstoragearea_impl.cc)。上面需要的WebStorageArea接口的实现是WebStorageAreaImpl在chrome里实现的(在WebKit之外)。让我有些惊讶的是,这些代码居然是放在renderer目录下的。后来想了一下,Storage与renderer没关系,但是这些代码是在render进程程执行的。每个标签都有一个Render进程,多个标签可能是同一个domain,也就是会存取同一个Storage,出于性能和共享考虑,所以把真正执行文件系统(数据库)的操作放在服务进程里了,这个模块是客户端的代理。
void WebStorageAreaImpl::setItem(    const WebString& key, const WebString& value, const WebURL& page_url,    WebStorageArea::Result& result) {  if (!cached_area_->SetItem(connection_id_, key, value, page_url))    result = ResultBlockedByQuota;  else    result = ResultOK;}bool DOMStorageCachedArea::SetItem(int connection_id,                                   const base::string16& key,                                   const base::string16& value,                                   const GURL& page_url) {  // A quick check to reject obviously overbudget items to avoid  // the priming the cache.  if (key.length() + value.length() > kPerStorageAreaQuota)    return false;  PrimeIfNeeded(connection_id);  base::NullableString16 unused;  if (!map_->SetItem(key, value, &unused))    return false;  // Ignore mutations to 'key' until OnSetItemComplete.  ignore_key_mutations_[key]++;  proxy_->SetItem(      connection_id, key, value, page_url,      base::Bind(&DOMStorageCachedArea::OnSetItemComplete,                 weak_factory_.GetWeakPtr(), key));  return true;}
  • 3.服务器及数据库(content/browser/dom_storage/dom_storage_area.cc)。这个是在浏览器的主进程里执行的,数据库使用的Sqlite。
bool DOMStorageArea::SetItem(const base::string16& key,                             const base::string16& value,                             base::NullableString16* old_value) {  if (is_shutdown_)    return false;  InitialImportIfNeeded();  if (!map_->HasOneRef())    map_ = map_->DeepCopy();  bool success = map_->SetItem(key, value, old_value);  if (success && backing_ &&      (old_value->is_null() || old_value->string() != value)) {    CommitBatch* commit_batch = CreateCommitBatchIfNeeded();    commit_batch->changed_values[key] = base::NullableString16(value, false);  }  return success;}

转载地址:http://dawkk.baihongyu.com/

你可能感兴趣的文章