美文网首页
ReactNative fetch源码分析

ReactNative fetch源码分析

作者: LaxusJ | 来源:发表于2019-11-03 21:10 被阅读0次

    原生分析的是安卓端

    核心代码

    //react-native/vendor/core/wehatwg-fetch.js
    self.fetch = function(input, init) {
        return new Promise(function(resolve, reject) {
          var request = new Request(input, init);
          var xhr = new XMLHttpRequest();
    
          xhr.onload = function() {
            var options = {
              status: xhr.status,
              statusText: xhr.statusText,
              headers: parseHeaders(xhr.getAllResponseHeaders() || ''),
            };
            options.url =
              'responseURL' in xhr
                ? xhr.responseURL
                : options.headers.get('X-Request-URL');
            var body = 'response' in xhr ? xhr.response : xhr.responseText;
            resolve(new Response(body, options));
          };
    
          xhr.onerror = function() {
            reject(new TypeError('Network request failed'));
          };
    
          xhr.ontimeout = function() {
            reject(new TypeError('Network request failed'));
          };
    
          xhr.open(request.method, request.url, true);
    
          if (request.credentials === 'include') {
            xhr.withCredentials = true;
          } else if (request.credentials === 'omit') {
            xhr.withCredentials = false;
          }
    
          request.headers.forEach(function(value, name) {
            xhr.setRequestHeader(name, value);
          });
    
          xhr.send(
            typeof request._bodyInit === 'undefined' ? null : request._bodyInit,
          );
        });
      };
    
    // node_modules/react-native/Libraries/Network/XMLHttpRequest.js
    send(data: any): void {
        if (this.readyState !== this.OPENED) {
          throw new Error('Request has not been opened');
        }
        if (this._sent) {
          throw new Error('Request has already been sent');
        }
        this._sent = true;
        const incrementalEvents =
          this._incrementalEvents || !!this.onreadystatechange || !!this.onprogress;
    
        this._subscriptions.push(
          RCTNetworking.addListener('didSendNetworkData', args =>
            this.__didUploadProgress(...args),
          ),
        );
        this._subscriptions.push(
          RCTNetworking.addListener('didReceiveNetworkResponse', args =>
            this.__didReceiveResponse(...args),
          ),
        );
        this._subscriptions.push(
          RCTNetworking.addListener('didReceiveNetworkData', args =>
            this.__didReceiveData(...args),
          ),
        );
        this._subscriptions.push(
          RCTNetworking.addListener('didReceiveNetworkIncrementalData', args =>
            this.__didReceiveIncrementalData(...args),
          ),
        );
        this._subscriptions.push(
          RCTNetworking.addListener('didReceiveNetworkDataProgress', args =>
            this.__didReceiveDataProgress(...args),
          ),
        );
        this._subscriptions.push(
          RCTNetworking.addListener('didCompleteNetworkResponse', args =>
            this.__didCompleteResponse(...args),
          ),
        );
    
        let nativeResponseType: NativeResponseType = 'text';
        if (this._responseType === 'arraybuffer') {
          nativeResponseType = 'base64';
        }
        if (this._responseType === 'blob') {
          nativeResponseType = 'blob';
        }
    
        invariant(this._method, 'Request method needs to be defined.');
        invariant(this._url, 'Request URL needs to be defined.');
        RCTNetworking.sendRequest(
          this._method,
          this._trackingName,
          this._url,
          this._headers,
          data,
          /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
           * when making Flow check .android.js files. */
          nativeResponseType,
          incrementalEvents,
          this.timeout,
          this.__didCreateRequest.bind(this),
          this.withCredentials,
        );
      }
    
    // node_modules/react-native/Libraries/Network/RCTNetworking.js
    sendRequest(
        method: string,
        trackingName: string,
        url: string,
        headers: Object,
        data: RequestBody,
        responseType: 'text' | 'base64',
        incrementalUpdates: boolean,
        timeout: number,
        callback: (requestId: number) => any,
        withCredentials: boolean,
      ) {
        const body = convertRequestBody(data);
        if (body && body.formData) {
          body.formData = body.formData.map(part => ({
            ...part,
            headers: convertHeadersMapToArray(part.headers),
          }));
        }
        const requestId = generateRequestId();
        RCTNetworkingNative.sendRequest(
          method,
          url,
          requestId,
          convertHeadersMapToArray(headers),
          {...body, trackingName},
          responseType,
          incrementalUpdates,
          timeout,
          withCredentials,
        );
        callback(requestId);
      }
    

    应用到XMLHttpRequest

    https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest

    调用流程

    fetch
    xhr.send -->
    RCTNetworking.android.js
    RCTNetworking.sendRequest -->
    走到native调用到NetworkingModule
    NetworkingModule.sendRequest

    取消请求

    XMLHttpRequest.js
    abort(): void {
        this._aborted = true;
        if (this._requestId) {
          RCTNetworking.abortRequest(this._requestId);
        }
        // only call onreadystatechange if there is something to abort,
        // below logic is per spec
        if (
          !(
            this.readyState === this.UNSENT ||
            (this.readyState === this.OPENED && !this._sent) ||
            this.readyState === this.DONE
          )
        ) {
          this._reset();
          this.setReadyState(this.DONE);
        }
        // Reset again after, in case modified in handler
        this._reset();
      }
    

    相关文章

      网友评论

          本文标题:ReactNative fetch源码分析

          本文链接:https://www.haomeiwen.com/subject/dqdyectx.html