• LocalStorage在Chrome里的实现


    前段时间我们在实现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<v8::Value>& 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;
    }
  • 相关阅读:
    UI自动化测试框架Cypress介绍和使用
    uniapp webview引入另一个uniapp打包的h5传值问题
    uniapp文件下载blob问题,uniapp使用webview引入另一个uniapp的h5时h5中的文件下载后blob,无法打开blob文件
    Maven把本地jar 加入jar库
    maven引入依赖问题
    swoole 进程模型
    Mac 风扇呼呼响的解决办法
    git push rejected 问题
    Mac touchbar 的用途
    查看路由表信息
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13333011.html
Copyright © 2020-2023  润新知