Ajax在浏览器上具体是如何执行的(3)

最后一讲,说说readystatechange,前一篇文章说过webkit的请求方式,以及如何返回数据,如何实现的异步等,今天讲整个ajax请求的最后一步,请求回来的数据是如何使用的

第一篇(http://www.ltplayer.com/blog/2018/12/24/ajax1/)文章说过

webkit会使用setJSXMLHttpRequestOnreadystatechange将你的onreadystatechange设置,那么再请求完成后,它就会去调用它,就是使用下面的函数完成

void XMLHttpRequest::callReadyStateChangeListener()
{
    if (!scriptExecutionContext())
        return;

    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willChangeXHRReadyState(scriptExecutionContext(), this);

    if (m_async || (m_state <= OPENED || m_state == DONE))
        m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().readystatechangeEvent), m_state == DONE ? FlushProgressEvent : DoNotFlushProgressEvent);

    InspectorInstrumentation::didChangeXHRReadyState(cookie);

    if (m_state == DONE && !m_error) {
        InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLoadXHR(scriptExecutionContext(), this);
        m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadEvent));
        InspectorInstrumentation::didLoadXHR(cookie);
        m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadendEvent));
    }
}

callReadyStateChangeListener的函数会执行回调函数,然后通过你要调用的属性,执行不同的方法和获取属性

xmlhttp.readyState会调用jsXMLHttpRequestReadyState

JSValue jsXMLHttpRequestReadyState(ExecState* exec, JSValue slotBase, const Identifier&)
{
    JSXMLHttpRequest* castedThis = static_cast<JSXMLHttpRequest*>(asObject(slotBase));
    UNUSED_PARAM(exec);
    XMLHttpRequest* impl = static_cast<XMLHttpRequest*>(castedThis->impl());
    JSValue result = jsNumber(impl->readyState());
    return result;
}

xmlhttp.status会调用jsXMLHttpRequestStatus

JSValue jsXMLHttpRequestStatus(ExecState* exec, JSValue slotBase, const Identifier&)
{
    JSXMLHttpRequest* castedThis = static_cast<JSXMLHttpRequest*>(asObject(slotBase));
    ExceptionCode ec = 0;
    XMLHttpRequest* impl = static_cast<XMLHttpRequest*>(castedThis->impl());
    JSC::JSValue result = jsNumber(impl->status(ec));
    setDOMException(exec, ec);
    return result;
}

xmlhttp.responseText会调用responseText,因为有可能发生错误而获取不到数据,所以有判断,如果失败则返回jsUndefined(),也就是javascript里的undefined

JSValue JSXMLHttpRequest::responseText(ExecState* exec) const
{
    ExceptionCode ec = 0;
    String text = impl()->responseText(ec);
    if (ec) {
        setDOMException(exec, ec);
        return jsUndefined();
    }
    return jsOwnedStringOrNull(exec, text);
}

执行每个函数或是获取某个属性都有发生错误,所以,每个函数都定义了一个ExceptionCode类型的变量,执行后返回值

typedef int ExceptionCode;

在每次返回后检查ec的值,如果错误就执行throwError(exec, errorObject);

void setDOMException(ExecState* exec, ExceptionCode ec)
{
    if (!ec || exec->hadException())
        return;

    // FIXME: All callers to setDOMException need to pass in the right global object
    // for now, we're going to assume the lexicalGlobalObject.  Which is wrong in cases like this:
    // frames[0].document.createElement(null, null); // throws an exception which should have the subframes prototypes.
    JSDOMGlobalObject* globalObject = deprecatedGlobalObjectForPrototype(exec);

    ExceptionCodeDescription description(ec);

    JSValue errorObject;
    switch (description.type) {
        DOM_EXCEPTION_INTERFACES_FOR_EACH(TRY_TO_CREATE_EXCEPTION)
    }

    ASSERT(errorObject);
    throwError(exec, errorObject);
}

以上就是回调函数的执行。