2023年 2月 24日 来源: 新华社微博 字号:默认 超大

Promise基本使用

Promise是异步编程的一种解决方案,用于一个异步操作的最终完成(或失败)及其结果值的表示,比传统的回调函数方案更加合理。

var promise = new Promise((resolve, reject) => {/* executor函数 */
    // ... some code
    if (/* 异步操作成功 */){
        resolve(value);
    } else {
        reject(error);
    }
});
promise.then((value) => {
    //success
}, (error) => {
    //failure
})

简单实用

function timeout(ms) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, ms, 'done');
    });
}
timeout(2000).then((value) => {
    console.log(value); //done
});
var timeoutID = scope.setTimeout(function, [delay, arg1, arg2, ...]);

arg1, ..., argN 可选

附加参数,一旦定时器到期,它们会作为参数传递给function

  1. Promise对象在创建后立即执行,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行。
  2. 如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个Promise 实例。
const p = new Promise((resolve,reject) => {
    return reject(new Error('err')); //reject方法的作用,等同于抛出错误
    //throw new Error('err');
});
p.then(null, (err) => {
    console.log(err);  //Err: err
});
//--------等价写法---------
p.catch(err => {
    console.log(err); //Err: err
})

一般总是建议,Promise 对象后面要跟catch方法,这样可以处理 Promise内部发生的错误。catch方法返回的还是一个 Promise 对象,因此后面还可以接着调用then方法。

new Promise(() => {
    throw new Error('err1');
})
    .then(() => {console.log(1);})
    .then(() => {console.log(2);})
    .catch((err) => {
        console.log(err); //Err: err1
        throw  new Error('err2');
    })
    .catch((err) => {console.log(err);})//Err: err2

Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。 即:当前catch方法可以捕获上一个catch方法(包括上一个catch)到当前catch(不包括当前catch)方法之间所有的错误,如果没有错误,则当前catch方法不执行。

// bad
new Promise()
    .then((data) => {/* success */ }, (err) => {/* error */ });
// good
new Promise()
    .then((data) => { /* success */ })
    .catch((err) => {/* error */ });

一般来说,不要在then方法里面定义Reject状态的回调函数(即then的第二个参数),总是使用catch方法。第二种写法要好于第一种写法,理由是第二种写法可以捕获前面then方法执行中的错误,也更接近同步的写法。

vue里的export default

export命令用于规定模块的对外接口。

一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};

export命令对外输出了指定名字的变量(变量也可以是函数或类)

export default命令的区别:import命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。

export default命令,为模块指定默认输出。

与export命令的区别:其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。

// export-default.js
export default function () {
  console.log('foo');
}
// import-default.js
import customName from './export-default';
customName(); // 'foo'

new VUE()

new Vue({
  render: h => h(App),
}).$mount("#app")

render函数是vue通过js渲染dom结构的函数createElement,约定可以简写为h

实际缩写前为:

render:function(createElement){
   return createElement(App);
}

实际渲染

import App from './App'
import Vue from 'vue'
new Vue({
  el:'#root',
  template:'<App></App>',
  components:{
    App
  }
})

在Vue构造函数时,需要配置一个el属性,如果没有没有el属性时,可以使用.$mount('#app')进行挂载。

// 配置了el属性:
new Vue({
    el:"#app",
    router
});
// 如果没有配置el属性,可以使用手动挂载$mount("#app")
new Vue({
    router
}).$mount('#app');
// 该方法是直接挂载到入口文件index.html 的 id=app 的dom 元素上的

render:h=>h(App)

1、ES6的写法,表示Vue实例选项对象的render方法作为一个函数,接受传入的参数h函数,返回h(App)的函数调用结果
2、Vue在创建Vue实例时,通过调用render方法来渲染实例的DOM树
3、Vue在调用render方法时,会传入一个createElement函数作为参数,也就是这里的h的实参是createElement函数,然后createElement会以App为参数进行调用。

Vue.use()的作用及原理

官方对 Vue.use() 方法的说明:通过全局方法 Vue.use() 使用插件,Vue.use 会自动阻止多次注册相同插件,它需要在你调用 new Vue() 启动应用之前完成,Vue.use() 方法至少传入一个参数,该参数类型必须是 Object 或 Function,如果是 Object 那么这个 Object 需要定义一个 install 方法,如果是 Function 那么这个函数就被当做 install 方法。在 Vue.use() 执行时 install 会默认执行,当 install 执行时第一个参数就是 Vue,其他参数是 Vue.use() 执行时传入的其他参数。就是说使用它之后调用的是该组件的install 方法。

Vue.use是用来安装插件的。

它在使用时实际是调用了该插件的install方法,所以引入的当前插件如果含有install方法我们就需要使用Vue.use(),例如在Vue中引用Element如下:

import Vue from 'vue'
import Element from 'element-ui'
Vue.use(Element)

因为在Element源码中会暴露除install方法,所以才需要用Vue.use()引入。

例如:

vueRouter需要在install方法,对Vue实例做一些自定义化的操作:比如在vue.prototype中添加$router、$route属性、注册组件

而axios是基于Promise封装的库,是完全独立于Vue的,根本不需要挂载在Vue上也能实现发送请求。

vue-router 为什么需要放到 new Vue({router}) options 里

插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:

添加全局方法或者属性。如: vue-custom-element
添加全局资源:指令/过滤器/过渡等。如 vue-touch
通过全局混入来添加一些组件选项。如 vue-router
添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router

使用插件也很简单,通过全局方法 Vue.use() 使用插件,注意它的调用需要在 new Vue() 之前。

但是在使用 vue-router 插件时还需要增加一个 options

// 调用 `router.install(Vue)`
Vue.use(router)
new Vue({
  // ...组件选项
  router
})

hash 路由和 history 路由

  1. hash 路由:监听 url 中 hash 的变化,然后渲染不同的内容,这种路由不向服务器发送请求,不需要服务端的支持;
  2. history 路由:监听 url 中的路径变化,需要客户端和服务端共同的支持;

hash

—— 即地址栏 URL 中的 # 符号

比如这个 URL:http://www.aaa.com/#/hello,hash 的值为 #/hello。它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。

history

—— 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)
这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。

Hash 模式是使用 URL 的 Hash 来模拟一个完整的 URL,因此当 URL 改变的时候页面并不会重载。History 模式则会直接改变 URL,所以在路由跳转的时候会丢失一些地址信息,在刷新或直接访问路由地址的时候会匹配不到静态资源。因此需要在服务器上配置一些信息,让服务器增加一个覆盖所有情况的候选资源,比如跳转 index.html 什么的

hash路由 优缺点

History(browser)路由 优缺点

$route和$router的区别

1.$router是VueRouter的一个对象,通过Vue.use(VueRouter)和Vue构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由,包含了许多关键的对象和属性。

2.$route是一个跳转的路由对象,每一个路由都会有一个$route对象,是一个局部的对象,可以获取对应的name,path,params,query等

全局事件总线

全局事件总线说到底就是个对象,我们通常就是用vm对象作为全局事件总线使用
把vm对象添加到Vue原型对象 就形成全局事件总线(vm)

1、所有的组件对象必须都能看得到这个总线对象,因此我们把这个对象放在了Vue原型
2、这个事件总线对象必须能调用$on和$emit方法(总线对象必须是Vue的实例化对象或者是组件对象)

1、vm.$on( event, callback )

监听当前实例上的自定义事件。事件可以由vm.$emit触发。回调函数会接收所有传入事件触发函数的额外参数。

2、vm.$emit( event, […args] )

触发当前实例上的事件。附加参数都会传给监听器回调,如果没有参数,形式为vm.$emit(event)

3、vm.$off( [event, callback] )

移除自定义事件监听器。