前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Angular 从入坑到挖坑 - HTTP 请求概览

Angular 从入坑到挖坑 - HTTP 请求概览

作者头像
程序员宇说
发布于 2020-03-24 09:27:17
发布于 2020-03-24 09:27:17
5.5K00
代码可运行
举报
文章被收录于专栏:程序员宇说程序员宇说
运行总次数:0
代码可运行

一、Overview

angular 入坑记录的笔记第四篇,介绍在 angular 中如何通过 HttpClient 类发起 http 请求,从而完成与后端的数据交互。

对应官方文档地址:

配套代码地址:angular-practice/src/http-guide

二、Contents

  1. Angular 从入坑到弃坑 - Angular 使用入门
  2. Angular 从入坑到挖坑 - 组件食用指南
  3. Angular 从入坑到挖坑 - 表单控件概览
  4. Angular 从入坑到挖坑 - HTTP 请求概览

三、Knowledge Graph

四、Step by Step

4.1、与后端进行数据交互
4.1.1、前置工作

在前端项目与后端进行数据交互时,绝大多数都是通过 HTTP 协议进行的,现代浏览器支持两种方式向后端发起 HTTP 请求:XMLHttpRequest 和 fetch

在以前的项目中,通常使用 jquery 的简化版 ajax 请求向后端请求数据,归根到底最终还是通过 XMLHttpRequest 与后端进行数据交互

在 Angular 中, 为了简化 XMLHttpRequest 的使用,框架提供了 HttpClient 类来封装 HTTP API,用来实现前端与后端的数据交互。

在使用之前,首先需要在应用的根模块中,引入 HttpClientModule 模块,并添加到 imports 数组中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

// 添加对于 HttpClientModule 模块的引用
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule // 添加到根应用模块中
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

在需要使用到的地方,引入 HttpClient 类,然后通过依赖注入的方式注入到应用类中

在通常情况下,我们需要将与后端进行交互的行为封装成服务,在这个服务中完成对于获取到的数据的处理,之后再注入到需要使用该服务的组件中,从而确保组件中仅仅包含的是必要的业务逻辑行为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Injectable } from '@angular/core';

// 引入 HttpClient 类
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class AntiMotivationalQuotesServicesService {

  // 通过构造函数注入的方式依赖注入到使用的类中
  constructor(private http: HttpClient) { }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Component, OnInit } from '@angular/core';

// 引入服务
import { AntiMotivationalQuotesServicesService } from './../services/anti-motivational-quotes-services.service';

@Component({
  selector: 'app-anti-motivational-quotes',
  templateUrl: './anti-motivational-quotes.component.html',
  styleUrls: ['./anti-motivational-quotes.component.scss']
})
export class AntiMotivationalQuotesComponent implements OnInit {

  // 通过构造函数注入的方式使用服务
  constructor(private services: AntiMotivationalQuotesServicesService) { }

  ngOnInit(): void {
  }

}
4.1.2、从服务端获取数据

这里使用到的后端接口是掘金上一位朋友开发的毒鸡汤接口(https://api.tryto.cn/djt/text),所有权归属于小咸鱼丶

通过使用 postman 进行接口调用可以发现,接口返回的响应信息如下

在项目中创建一个接口,按照后端返回的数据信息进行属性的定义,用来映射请求的响应信息(Angular 只能将请求响应对象转换成接口类型,不能自动转换成类实例)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ng g interface interfaces/get-quotes-response-model
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export interface GetQuotesResponseModel {
  /**
   * 接口响应码
   */
  code: number;
  /**
   * 响应信息
   */
  msg: string;
  /**
   * 响应数据
   */
  data: ResponseData;
  /**
   * 响应时间
   */
  time: number;
}

/**
 * 接口响应的内容信息
 */
interface ResponseData {
  /**
   * 毒鸡汤
   */
  content: string;
  /**
   * 热度
   */
  hots: number;
}

在服务中,引入请求响应对象的接口定义,然后设定 get 请求的响应对象为 GetQuotesResponseModel,之后在使用时就可以以一种结构化数据的方式获取请求返回的数据信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

// 引入 HttpClient 类
import { HttpClient } from '@angular/common/http';

// 引入接口响应类
import { GetQuotesResponseModel } from '../interfaces/get-quotes-response-model';

@Injectable({
  providedIn: 'root'
})
export class AntiMotivationalQuotesServicesService {

  // 通过构造函数注入的方式依赖注入到使用的类中
  constructor(private http: HttpClient) { }

  /**
   * 通过 get 请求获取毒鸡汤信息
   */
  getAntiMotivationalQuotes(): Observable<GetQuotesResponseModel> {
    const url = 'https://api.tryto.cn/djt/text';
    return this.http.get<GetQuotesResponseModel>(url);
  }
}

在组件中,通过调用注入的服务类完成接口数据的获取,因为是以一种结构化对象的形式获取到接口返回的数据,因此这里可以直接通过对象属性获取到指定的属性信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Component, OnInit } from '@angular/core';

// 引入服务
import { AntiMotivationalQuotesServicesService } from './../services/anti-motivational-quotes-services.service';

// 引入接口响应对象
import { GetQuotesResponseModel } from '../interfaces/get-quotes-response-model';

@Component({
  selector: 'app-anti-motivational-quotes',
  templateUrl: './anti-motivational-quotes.component.html',
  styleUrls: ['./anti-motivational-quotes.component.scss']
})
export class AntiMotivationalQuotesComponent implements OnInit {

  public quoteResponse: GetQuotesResponseModel;

  // 通过构造函数注入的方式使用服务
  constructor(private services: AntiMotivationalQuotesServicesService) { }

  ngOnInit(): void {
  }

  /**
   * 获取毒鸡汤
   */
  getQuotes() {
    this.services.getAntiMotivationalQuotes().subscribe((response: GetQuotesResponseModel) => {
      this.quoteResponse = response;
    });
  }
}

因为最终需要的信息是接口返回的响应信息对象中的一个属性,因此这里需要使用安全导航运算符(?)来确保模板的渲染不会因为空指针错误而中断

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<p>
  <button (click)="getQuotes()">获取毒鸡汤</button>
</p>
<p>
  接口返回信息: {{quoteResponse | json}}
</p>
<i>
  毒鸡汤:{{quoteResponse?.data?.content}}
</i>

在执行服务中的方法时,有时会存在没有回调函数的情况,此时也必须执行 subscribe 方法,否则服务中的 HTTP 请求是没有真正发起的

服务中的 getAntiMotivationalQuotes 只能获取到接口返回的 body 里面的信息,某些情况下需要获取到完整的响应信息,此时需要通过 observe 参数来告诉 HttpClient 此方法需要返回完整的响应信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

// 引入 HttpClient 类
import { HttpClient, HttpResponse } from '@angular/common/http';

// 引入接口响应类
import { GetQuotesResponseModel } from '../interfaces/get-quotes-response-model';

@Injectable({
  providedIn: 'root'
})
export class AntiMotivationalQuotesServicesService {

  // 通过构造函数注入的方式依赖注入到使用的类中
  constructor(private http: HttpClient) { }

  /**
   * 获取完整的接口请求信息
   */
  getAntiMotivationalQuotesResponse(): Observable<HttpResponse<GetQuotesResponseModel>> {
    const url = 'https://api.tryto.cn/djt/text';
    return this.http.get<GetQuotesResponseModel>(url, { observe: 'response' });
  }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { HttpResponse } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';

// 引入服务
import { AntiMotivationalQuotesServicesService } from './../services/anti-motivational-quotes-services.service';

// 引入接口响应对象
import { GetQuotesResponseModel } from '../interfaces/get-quotes-response-model';

@Component({
  selector: 'app-anti-motivational-quotes',
  templateUrl: './anti-motivational-quotes.component.html',
  styleUrls: ['./anti-motivational-quotes.component.scss']
})
export class AntiMotivationalQuotesComponent implements OnInit {

  public quoteResponseInfo: HttpResponse<GetQuotesResponseModel>;

  // 通过构造函数注入的方式使用服务
  constructor(private services: AntiMotivationalQuotesServicesService) { }

  ngOnInit(): void {
  }

  /**
   * 获取毒鸡汤接口完整的请求信息
   */
  getQuotesResponse() {
    this.services.getAntiMotivationalQuotesResponse().subscribe((response: HttpResponse<GetQuotesResponseModel>) => {
      this.quoteResponseInfo = response;
    });
  }
}

HttpClient 默认的返回信息格式都是 json 对象,在后端接口返回的并不是 json 对象的情况下,需要手动的设置响应类型(text、blob、arraybuffer...)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

// 引入 HttpClient 类
import { HttpClient, HttpResponse } from '@angular/common/http';

// 引入接口响应类
import { GetQuotesResponseModel } from '../interfaces/get-quotes-response-model';

@Injectable({
  providedIn: 'root'
})
export class AntiMotivationalQuotesServicesService {

  // 通过构造函数注入的方式依赖注入到使用的类中
  constructor(private http: HttpClient) { }
  
  /**
   * 获取响应类型非 json 对象的信息
   */
  getYuiterSitemap(): Observable<string> {
    const url = 'https://yuiter.com/sitemap.xml';
    return this.http.get(url, { responseType: 'text' });
  }
}
4.1.3、提交数据到服务端

在同后端接口进行交互时,获取数据一般用的是 get 请求,而当进行数据新增、更新、删除时则会使用 post、put、delete 这三个 HTTP 谓词

在毒鸡汤这个接口中,可以使用 post 方式调用 https://api.tryto.cn/djt/submit 进行毒鸡汤的提交

根据 postman 的调用示例,在服务中定义一个方法用来提交毒鸡汤信息,这里的 SetQuotesResponseModel 为接口返回的响应对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

// 引入 HttpClient 类
import { HttpClient, HttpResponse } from '@angular/common/http';

// 引入接口响应类
import { SetQuotesResponseModel } from '../interfaces/set-quotes-response-model';

@Injectable({
  providedIn: 'root'
})
export class AntiMotivationalQuotesServicesService {

  // 通过构造函数注入的方式依赖注入到使用的类中
  constructor(private http: HttpClient) { }

  /**
   * 提交毒鸡汤信息
   * @param content 毒鸡汤
   */
  submitAntiMotivationalQuote(content: string): Observable<SetQuotesResponseModel> {
    const url = 'https://api.tryto.cn/djt/submit';
    return this.http.post<SetQuotesResponseModel>(url, {
      content
    });
  }
}

因为这里是以默认的表单提交的方式进行的数据提交,当后端需要修改请求的 body 格式时,则需要我们修改请求的 MIME 类型

当需要更改请求的 MIME 类型或是需要添加授权访问的 token 信息这一类的操作时,需要在使用 HttpClient 提供的请求方法时添加上 HTTP 请求头配置信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

// 引入 HttpClient 类
import { HttpClient, HttpResponse, HttpHeaders } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class AntiMotivationalQuotesServicesService {

  // 通过构造函数注入的方式依赖注入到使用的类中
  constructor(private http: HttpClient) { }

  public httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json',
      'Authorization': 'token'
    })
  };

  /**
   * 修改请求头信息
   */
  submitWithOptions() {
    const url = '';
    return this.http.post(url, {
      data: ''
    }, this.httpOptions);
  }
}
4.2、捕获错误信息
4.2.1、获取错误信息

在涉及到前后端交互的过程中,不可避免会出现各种状况,在出现错误时,可以在 subscribe 方法中,添加第二个回调方法来获取错误信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
getQuotes() {
    this.services.getAntiMotivationalQuotes().subscribe((response: GetQuotesResponseModel) => {
      this.quoteResponse = response;
    }, error => {
      console.error(error);
    });
}

在处理错误信息的回调方法中,方法返回了一个 HttpErrorResponse 对象来描述错误信息

因为这里的错误更多是服务在与后端进行通信产生的错误,因此对于错误信息的捕获和处理更应该放到服务中进行,而在组件处仅显示错误提示

在服务中定义一个错误处理器,用来处理与后端请求中发生的错误

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';

// 引入 HttpClient 类
import { HttpClient, HttpResponse, HttpHeaders, HttpErrorResponse } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class AntiMotivationalQuotesServicesService {

  // 通过构造函数注入的方式依赖注入到使用的类中
  constructor(private http: HttpClient) { }

  /**
   * 通过 get 请求获取毒鸡汤信息
   */
  getAntiMotivationalQuotes(): Observable<GetQuotesResponseModel> {
    const url = 'https://api.tryto.cn/djt/text32';
    return this.http.get<GetQuotesResponseModel>(url)
      .pipe(
        catchError(this.handleError)
      );
  }

  /**
   * 错误信息捕获处理
   * @param error 错误信息
   */
  private handleError(error: HttpErrorResponse) {

    if (error.error instanceof ErrorEvent) {
      // 客户端本身引起的错误信息
      console.error(`客户端错误:${error.error.message}`);
    } else {
      // 服务端返回的错误信息
      console.error(`服务端错误:HTTP 状态码:${error.status} \n\r 错误信息:${JSON.stringify(error.error)}`);
    }

    // 反馈给用户的错误信息(用于组件中使用 error 回调时的错误提示)
    return throwError('不好的事情发生了,毕竟我们都有不顺利的时候。。。');
  }
}

当请求发生错误时,通过在 HttpClient 方法返回的 Observable 对象中使用 pipe 管道将错误传递给自定义的错误处理器,从而完成捕获错误信息的后续操作

4.2.2、请求重试

某些情况下存在因为特殊原因导致短时间的请求失败,这时可以在 pipe 管道中,当请求失败后,使用 retry 方法进行多次的请求重试,在进行了多次重试后还是无法进行数据通信后,则进行错误捕获

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
getAntiMotivationalQuotes(): Observable<GetQuotesResponseModel> {
    const url = 'https://api.tryto.cn/djt/text32';
    return this.http.get<GetQuotesResponseModel>(url)
      .pipe(
        retry(3), // 重试三次
        catchError(this.handleError) // 捕获错误信息
      );
}
4.3、请求和响应拦截

在向服务器发起请求时,一般是需要我们在请求头中添加上授权的 token 信息,与其当后端接口返回我们无权访问时再来处理,是不是可以在发起请求前去进行拦截判断,如果不包含 token 信息,则将允许访问的 token 信息添加到请求中

同样的,当已经定义好后端返回什么信息代表请求出错 or 直接根据后端返回的请求状态码判断请求出错时,完全可以通过对接口返回的响应进行拦截,直接拦截掉请求出错的情况,从而不需要在后续的业务逻辑代码中再进行判断请求是否成功

4.3.1、自定义拦截器

在 Angular 中可以新建一个继承于 HttpInterceptor 接口的拦截器类,通过实现 intercept 方法来对请求进行拦截处理

ASP.NET Core 中的中间件相似,我们可以在请求中添加多个的拦截器,构成一个拦截器链。当一个拦截器已经处理完成时,需要通过 next 对象将 HTTP 请求传递到下一个拦截器,否则,整个请求将会中断。如果当前的拦截器已经是整个拦截器链的最后一个,则会将请求发送到后端接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs/internal/Observable';
import { Injectable } from '@angular/core';
import { tap, finalize } from 'rxjs/operators';

/**
 * 通过添加 Injectable 特性,表明可以通过依赖注入的方式进行创建
 */
@Injectable()
export class LoggingInterceptor implements HttpInterceptor {
  /**
   * 请求拦截
   * @param req http 请求
   * @param next 下一个拦截器
   */
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    // 开始时间
    const started = Date.now();

    let msg: string;

    // 将 http 请求信息传递给下一个拦截器
    return next.handle(req)
      .pipe(
        tap(
          // 捕获当前请求是否成功 or 失败

          // 1、通过判断响应的类型是否为 HttpResponse 来判断请求是否成功
          event => msg = event instanceof HttpResponse ? '请求成功' : '请求失败',

          // 2、如果存在了 error 回调,则请求失败
          error => msg = '请求失败'
        ), finalize(() => {
          const elapsed = Date.now() - started;
          console.log(`请求方式:${req.method} 请求地址:${req.urlWithParams} 响应耗时:${elapsed} ms 请求结果:${msg}`);
        }));
  }
}

当定义好拦截器后,与其它的自定义服务一样,我们需要添加到根模块的 providers 中,因为可能会存在定义多个拦截器的情况,这里可以通过定义一个 typescript 文件用来导出我们需要添加的拦截器信息

因为会存在定义多个拦截器的情况,所以这里需要指定 multi 属性为 true

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { HTTP_INTERCEPTORS } from '@angular/common/http';

// 需要添加的拦截器
import { LoggingInterceptor } from './logging-interceptor';

// 返回的拦截器数组
export const HttpInterceptorProviders = [
  { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true }
];

由于拦截器具有将发送到服务端的 HTTP 请求进行监视、转化,以及拦截请求的响应信息的双重效果,因此当我们注册了多个拦截器时,在发送请求时会按照我们添加的顺序进行执行,而在接受到请求响应时,则是按照反过来的顺序进行执行

获取到导出的拦截器信息,就可以在根模块中去导入需要注册的拦截器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

// 添加自定义拦截器
import { HttpInterceptorProviders } from './http-interceptors/http-interceptor-providers';

@NgModule({
  declarations: [
    AppComponent,
    AntiMotivationalQuotesComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule // 添加到根应用模块中
  ],
  providers: [
    HttpInterceptorProviders
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
4.3.2、修改请求信息

由于一个请求可能会存在重试发起的情况,为了确保多次发起请求时的请求信息的不变性,对于 HttpRequest 和 HttpResponse 我们是不可以修改原始的对象属性值的

当我们需要对请求进行修改时,例如在请求的 header 中添加上 token 信息,此时我们需要先克隆一个原始的请求对象,在这个克隆后的请求上进行操作,最终将这个克隆后的请求传递给下一个拦截器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs/internal/Observable';
import { Injectable } from '@angular/core';
import { tap, finalize } from 'rxjs/operators';

/**
 * 通过添加 Injectable 特性,表明可以通过依赖注入的方式进行创建
 */
@Injectable()
export class LoggingInterceptor implements HttpInterceptor {
  /**
   * 请求拦截
   * @param req http 请求
   * @param next 下一个拦截器
   */
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    // 开始时间
    const started = Date.now();

    let msg: string;

    // 打印原始的请求信息
    console.log(`原始的请求信息:${JSON.stringify(req.headers)}`);

    // 获取请求中的 token 信息
    const token = req.headers.get('Authorization') || '';

    // 克隆请求信息
    const authReq = req.clone({
      headers: token === '' ? req.headers.set('Authorization', '123456') : req.headers
    });

    // 打印修改后的请求信息
    console.log(`克隆后的请求信息:${JSON.stringify(authReq.headers)}`);

    // 将克隆后的 http 请求信息传递给下一个拦截器
    return next.handle(authReq)
      .pipe(
        tap(
          // 捕获当前请求是否成功 or 失败

          // 1、通过判断响应的类型是否为 HttpResponse 来判断请求是否成功
          event => msg = event instanceof HttpResponse ? '请求成功' : '请求失败',

          // 2、如果存在了 error 回调,则请求失败
          error => msg = '请求失败'
        ), finalize(() => {
          const elapsed = Date.now() - started;
          console.log(`请求方式:${req.method} 请求地址:${req.urlWithParams} 响应耗时:${elapsed} ms 请求结果:${msg}`);
        }));
  }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-03-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
jquery的ready方法实现原理
应用jquery时 ready是一个非常常用的方法,我们常常会写 $(document).ready(function) 或 $(function) ready的作用 window.onload 必须等到页面内包括图片的所有元素加载完毕后才能执行,如果网页上有大量的图片,效果可想而知,用户可能在没有看到图片的时候,就已经开始操作页面了 所以window.onload 很难满足我们的需求 而ready是DOM结构绘制完毕后就执行,不必等到加载完毕 ready是如何实现的? ready是浏览器兼
dys
2018/04/03
1.5K0
jquery的ready方法实现原理
javascript-继承之jquery
jquery 截止到当前已经 3.3.1 版本了,如今随着各种浏览器的盛行,前端的框架层出不穷,jquery 独步天下,老夫写代码只用 jquery,拿起代码就是干的辉煌时代已经过去了。
chuchur
2022/10/25
1.1K0
javascript-继承之jquery
JS判断单、多张图片加载完成
在实际的运用中有这样一种场景,某资源加载完成后再执行某个操作,例如在做导出时,后端通过打开模板页生成PDF,并返回下载地址。这时前后端通常需要约定一个flag,用以标识模板准备就绪,可以生成PDF了。
疯狂的技术宅
2019/03/27
12.7K0
网站性能优化(三)异步加载脚本
原则上来说,HTML在使用<script>标签加载外部脚本文件时,会顺序下载,顺序执行,并阻碍其他资源文件的下载,比如图片(当然,如今主流浏览器是可以实现JS和CSS文件并行下载)。
娜姐
2022/05/13
1.4K0
网站性能优化(三)异步加载脚本
DOMContentLoaded和window.onload
相信写js的。都知道window.onload吧,可是并非每一个人都知道DOMContentLoaded,事实上即使你不知道。非常有可能你也常常使用了这个东西。
全栈程序员站长
2022/07/06
1.5K0
jquery $(document).ready()与window.onload的区别
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
奋飛
2019/08/15
2.4K0
Web 性能优化-首屏和白屏时间
白屏时间是指浏览器从响应用户输入网址地址,到浏览器开始显示内容的时间。 首屏时间是指浏览器从响应用户输入网络地址,到首屏内容渲染完成的时间。
李振
2021/11/26
3K0
Web 性能优化-首屏和白屏时间
JS完美收官之——js加载时间线
浏览器在开始运行一个页面的时候,首先它会初始化js功能,当js发挥它的功能时候,记录了一系列浏览器按照顺序做的事情,也就是一个执行顺序,谁在谁之前发生,谁在谁之后发生。
程序员法医
2022/08/11
1.3K0
JS完美收官之——js加载时间线
document.ready 与 window.onload的区别
document的ready事件通常会比window的onload事件先发生,为什么呢? 因为document的ready是在浏览器加载解析并构建完doc文档模型时发生的,而window的onload是整个文档的内容加载完成时才会发生。 当document文档正在加载时,返回"loading"。当文档结束渲染但在加载内嵌资源时,返回"interactive",并引发DOMContentLoaded事件。当文档加载完成时,返回"complete",并引发load事件。 readystatechange事件会在
smy
2018/04/03
1.4K0
前端开发工程师有必须重视的几个性能指标
前端开发工程师有有必要重视的几个功用方针 关于页面相应时间,有一条闻名的“2-5-8准则”。当用户访问一个页面: 在2秒内得到照应时,会感觉系统照应很快; 在2-5秒之间得到照应时,会感觉系统的照应速度还可以; 在5-8秒以内得到照应时,会感觉系统的照应速度很慢,但可以承受; 而逾越8秒后依然无法得到照应时,用户会感觉系统糟透了,进而选择脱离这个站点,或许主张第2次央求。 关于一个网站如果期望抓住用户,网站的速度以及稳定性是首战之地的。 从各式各样的前端监控平台中,你都可以获得页面许多的功用方针。本文将介绍
企鹅号小编
2018/02/12
6300
从零开始搭建前端数据监控系统(二)-前端性能监控方案调研
1. 业界案例 目前前端性能监控系统大致为分两类:以GA为代表的代码监控和以webpagetest为代表的工具监控。 代码监控依托于js代码并部署到需监控的页面,手动计算时间差或者使用浏览器的的API进行数据统计。 影响代码监控数据的因素有以下几种: 浏览器渲染机制; 浏览器对API的实现程度,比如performance API; 工具监控不用将统计代码部署到页面中,一般依托于虚拟机。以webpageTest为例,输入需统计的url并且选择运行次url的浏览器版本,webpageTest后台虚拟机对url进
寒月十八
2018/01/30
2.5K0
从零开始搭建前端数据监控系统(二)-前端性能监控方案调研
windows.onload()与$(document).ready()的区别
在jquery中,则使用$(document).ready()方法。下面介绍一下两者的区别。
山河木马
2019/03/05
9770
window.onload 与 $(document).ready()比较
ready事件发生在加载HTML文档之后,而onload事件发生在稍后,此时所有内容(例如图像)也已加载。
IT工作者
2022/01/25
1.6K0
HTML解析之DOMContentLoaded和onload
在很久很久以前,我在封装自己的JQuery库时就使用过DOMContentLoaded,觉得这个知识点看看别的文章就行了,不过现在我想把它记下来。
全栈程序员站长
2022/11/16
1.7K0
HTML解析之DOMContentLoaded和onload
domReady的理解
domReady是名为DOMContentLoaded事件的别称,当初始的HTML文档被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待样式表、图像和子框架的完全加载。
WindRunnerMax
2020/09/24
1K0
项目中遇到的bug(web前端-持续更新)
版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/article/details/51159370
空空云
2018/09/27
1K0
前端知识普及之页面加载
如果大家想继续看下面的内容的话,有一个要求,就是回答我一个问题: 你这样写过代码吗? window.onload = function(){ $(".gravatar").on('click',function(){ //... }); //以及其他操作DOM的节点 } 如果答案是 yes. 那么,bingo, 这里我们将深入讲解,这样写代码到底有没有IQ。 如果答案是 No. 那么,2333333, 你也可以看一下。 万一哪天用上了呢? 可能会有童鞋反问,那么,我
前朝楚水
2018/04/02
1.6K0
Js框架设计之DomReady
一、在介绍DomReady之前,先了解下相关的知识 1、HTML是一种标记语言,告诉我们这页面里面有什么内容,但是行为交互则要通过DOM操作来实现,但是注意:不要把尖括号里面的内容看作是DOM! 2、HTML是要通过浏览器解析之后才会转换成为DOM节点 一般地,但我们向浏览器中输入一个地址,开始加载页面到我们看到页面的内容为止,这期间就有一个DOM节点构建的过程(浏览器将HTML标签转换为DOM节点)。 当前页面上的所有的HTML标签都转换成DOM节点,这就叫DOM树建完,简称为DOMReady. 3、浏
郑小超.
2018/01/24
1.5K0
【博客同步】onload与ready对比
ready , onload 类函数 : JS的 window.onload 方法, jQuery 的 (document).ready 方法和 (window).load 方法 ready 事件的触发,表示文档结构已经加载完成(不包含图片等非文字媒体文件) onload / load 事件的触发,表示页面包含图片等文件在内的所有元素都加载完成
CS逍遥剑仙
2025/03/06
610
BAT及各大互联网公司2014前端笔试面试题--JavaScript篇
很多面试题是我自己面试BAT亲身经历碰到的。整理分享出来希望更多的前端er共同进步吧,不仅适用于求职者,对于巩固复习js更是大有裨益。 而更多的题目是我一路以来收集的,也有往年的,答案不确保一定正确,如有错误或有更好的解法,还请斧正。 附上第二篇:BAT及各大互联网公司2014前端笔试面试题--Html,Css篇 前面几题是会很基础,越下越有深度。  初级Javascript: 1.JavaScript是一门什么样的语言,它有哪些特点? 没有标准答案。 2.JavaScript的数据类型都有什么? 基本数
Sb_Coco
2018/05/28
1.5K0
推荐阅读
相关推荐
jquery的ready方法实现原理
更多 >
LV.2
京东软件开发工程师
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验