Typescrip异步函数Promise使用方式

JavaScript/前端
589
0
0
2023-03-09
标签   Promise
目录
  • Typescrip异步函数Promise
  • typescript- typescrip与react
  • 对象的类型
  • 数组类型
  • 函数类型
  • 类型断言
  • 内置对象
  • 泛型
  • React 中使用

Typescrip异步函数Promise

var p = new Promise(function (resolve, reject) {
    var x = 1;
    if (x > 0) {
        resolve({ msg: '异步调用成功', data: { x: 1, y: 2 } });
    }
    else {
        reject({ msg: '异步调用失败', data: {} });
    }
});
//异步调用结果
p.then(function (data) {
    console.log('OK');
    console.log(data);
    //console.log(data.msg,data.data);
})["catch"](function (err) {
    console.log(err);
});
//异步函数
function promiseFunc(t) {
    console.log("".concat(t / 1000, "\u79D2\u540E\u8C03\u7528\u5F02\u6B65"));
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, t, '异步调用完成');
    });
}
//调用异步函数
promiseFunc(1000).then(function (value) { console.log(value); });
var promiseAction = new Promise(function (resolve, reject) {
    console.log('执行了一些异步操作...');
    resolve('异步操作完成了!');
});
promiseAction.then(function (value) { console.log(value); });
// @ts-ignore
// const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
// let getDataAsync=(url)=>{
//     let p = new Promise((resolve, reject) => {
//         let c =new XMLHttpRequest();
//         c.open('GET',url);
//         c.onreadystatechange = h;
//         c.responseType = 'json';
//         c.setRequestHeader('Accept','application/json');
//         c.send();
//         function h(){
//             if(this.readyState!==4){return;}
//             if (this.status===200){
//                 console.log('请求成功返回:',this.status);
//                 resolve(this.response);
//             }else {
//                 reject(new Error(this.statusText));
//             }
//         }
//     });
//     return p;
// };
// getDataAsync('http://192.168.31.180/data.json')
// .then(data=>{console.log(data);})
// .catch(err=>{console.log(err);});
//通过https加载json数据
var url = 'https://img-home.csdnimg.cn/data_json/toolbar/toolbar1105.json';
var url1 = 'https://mp-api.iqiyi.com/base/api/1.0/get_role';
var GetJsonData = function (url) {
    var https = require('https');
    https.get(url, function (response) {
        var data = '';
        //数据正在接收中...
        response.on('data', function (chunk) {
            data += chunk;
        });
        //数据接收完成
        response.on('end', function () {
            console.log('同步请求数据完成:', JSON.parse(data));
        });
    }).on("error", function (error) {
        console.log("Error: " + error.message);
    });
};
GetJsonData(url);
//异步请求JSON数据实现
var GetJsonDataAsync = function (url) {
    var https = require('https');
    return new Promise(function (resolve, reject) {
        https.get(url, function (response) {
            var data = '';
            //数据正在接收中...
            response.on('data', function (chunk) {
                data += chunk;
            });
            //数据接收完成
            response.on('end', function () {
                //console.log(JSON.parse(data));
                resolve(data); //数据接收完成
            });
        }).on("error", function (error) {
            console.log("Error: " + error.message);
            reject(new Error(error.message));
        });
    });
};
//异步调用
GetJsonDataAsync(url).then(function (value) {
    console.log("======================下面为异步加载数据=================================");
    if (typeof value === "string") {
        console.log('异步加载请求数据完成:', JSON.parse(value));
    }
})["catch"](function (err) { console.log(err); });
//通过request库请求json数据,使用前 sudo npm i -g request安装包
var request = require('request');
request(url, function (error, response, body) {
    console.error('错误:', error);
    console.log('状态码:', response && response.statusCode);
    console.log('数据:', JSON.parse(body));
});
//异步方式
var RequestJsonAsync = function (url) {
    return new Promise(function (resolve, reject) {
        request(url, function (e, r, d) {
            if (null != e) {
                reject(new Error(e));
            }
            else {
                resolve(JSON.parse(d));
            }
        });
    });
};
RequestJsonAsync(url).then(function (value) {
    console.log("==============request异步加载json===============================");
    console.log(value);
})["catch"](function (err) { console.log(err); });
//nodejs needle库使用 ,使用前 npm i needle --save 安装包
var needle = require('needle');
needle.get(url, function (error, response) {
    if (!error && response.statusCode == 200)
        console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", response.body);
});
//异步模式
needle('get', url, { json: true }).then(function (resp) {
    if (resp.statusCode == 200) {
        console.log(">>>>>>>>>>>>>>异步模式>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", resp.body);
    }
})["catch"](function (err) { console.log(err); });
//使用axios库使用,axios直接异步  使用前安装 npm i -g axios --save
var axios = require('axios');
axios.get(url)
    .then(function (res) {
    console.log(res);
})["catch"](function (err) {
    console.log(err);
});
//axios支持多请求并发
axios.all([
    axios.get(url),
    axios.get(url1)
]).then(axios.spread(function (res1, res2) {
    console.log(res1);
    console.log(res2);
}))["catch"](function (err) {
    console.log(err);
});
//supertaget库使用
var superagent = require('superagent');
superagent.get(url)
    .end(function (err, res) {
    if (err) {
        return console.log(err);
    }
    console.log("superagent库调用==========>", res.body);
});
//fetch库使用 使用前安装 npm i node-fetch  3x版本只能import导入 --save  支持异步
// @ts-ignore
// import fetch from 'node-fetch'; //不能在模块之外使用
// fetch(url)
//     .then(res => res.json()) // expecting a json response
//     .then(json => {
//         console.log(json);
//     })
//     .catch(err => {
//         console.log(err);
//     });
var p1 = new Promise(function (resolve, reject) {
    resolve('p1 resolve');
});
var p2 = new Promise(function (resolve, reject) {
    resolve('p2 resolve');
});
//只要p1,p2中的其中一个有状态改变,马上返回pRace
var pRace = Promise.race([p1, p2]);//将多个Promise生成一个Promise
pRace.then(function (value) {
    console.log(value);
});

typescript- typescrip与react

对象的类型

接口 Interfaces 一般首字母大写

interface Person {
    readonly id: number; // 只读属性 不能修改
    name: string;
    age: number;
    age?: number;   // 可选
    [propName: string]: any; // 任意属性
    // 注意,
}
// 顺序 一般是 只读 -> 默认 -> 可选 -> 任意
let tom: Person = {
    name: 'Tom',
    age: 25
};

一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:

interface Person {
    name: string;
    age?: number;
    [propName: string]: string;
}
let tom: Person = {
    name: 'Tom',
    age: 25,     // 报错 需要是 任意属性的子集
    gender: 'male'
};

任意属性的值允许是 string,但是可选属性 age 的值却是 number,number 不是 string 的子属性,所以报错了

只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候 

interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}
let tom: Person = {
    name: 'Tom',
    gender: 'male'
};

tom.id = 89757;   // 报错,第一处是在对 tom 进行赋值的时候,没有给 id 赋值。 之后再赋值就报错

数组类型

「类型 + 方括号」表示法

let arr: number[] = [1, 2, 3, 4, 5]; // 表示 是数组, 并且数组元素只能为 number 类型

联合类型和数组的结合

// arr 表示 是数组, 并且数组元素只能为 number 和 string 类型
let arr: (number | string)[] = ['1', 'adaf', 2, 3, 5]

数组泛型

let arr: Array<number> = [1, 2, 3, 4, 5];

类数组

常见的类数组都有自己的接口定义,如 IArguments, NodeList, HTMLCollection 等

// error 函数中的 arguments 这也定义会报错
let args: number[] = arguments;
// success 改成
let args: IArguments = arguments;

函数类型

函数声明

function sum(x: number, y: number): number {
    return x + y;
}

函数表达式

let mySum = function (x: number, y: number): number {
    return x + y;
};

这是可以通过编译的,不过事实上,上面的代码只对等号右侧的匿名函数进行了类型定义,而等号左边的 mySum,是通过赋值操作进行类型推论而推断出来的。如果需要我们手动给 mySum 添加类型,则应该是这样:

let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y;
};

类型断言

function getLength(something: string | number): number {
    // 将他断言为 string
    if ((<string>something).length) {
        return (<string>something).length;
    } else {
        return something.toString().length;
    }
}

类型断言不是类型转换,断言成一个联合类型中不存在的类型是不允许的:

// error 
function toBoolean(something: string | number): boolean {
    return <boolean>something;
}
// Type 'number' is not comparable to type 'boolean'

内置对象

ECMAScript 的内置对象

Boolean、Error、Date、RegExp 等。

DOM 和 BOM 的内置对象

Document、HTMLElement、Event、NodeList 等。

泛型

是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]];
}

问题

type 和 Interfaces 的区别

React 中使用

import React, { MouseEvent, ReactNode } from 'react'
type Props = { 
 onClick(e: MouseEvent<HTMLElement>): void
 children?: ReactNode 
}
const Button = ({ onClick: handleClick, children }: Props) => (
  <button onClick={handleClick}>{children}</button>
)

高阶组件的使用方式

import React from 'react';
import { Form } from 'antd';
import { FormComponentProps } from 'antd/es/form';
interface IProps extends FormComponentProps {
  loading: boolean;
}
const Page: React.FC<IProps>  = (props) => {
  return (
     <div>Page</div>
  )
}
export default Form.create<IProps>()(Page)

对象类型取值

type DealWithProps = {
  onClose: Function;
  eventId: string;
  dealTime: any;
};
// 处理
const getOnDealWith = (parameObj: DealWithProps) => () => {
  // TODO 暂无接口
  for (let i in parameObj) {
    console.log(parameObj[i], typeof parameObj[i]);
      // 报错 
      /**
      Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'DealWithProps'.
  No index signature with a parameter of type 'string' was found on type 'DealWithProps'.ts(7053)
      **/
  }
};

Event 事件对象类型

常用 Event 事件对象类型:

  • ClipboardEvent<T = Element> 剪贴板事件对象
  • DragEvent<T = Element> 拖拽事件对象
  • ChangeEvent<T = Element> Change 事件对象
  • KeyboardEvent<T = Element> 键盘事件对象
  • MouseEvent<T = Element> 鼠标事件对象
  • TouchEvent<T = Element> 触摸事件对象
  • WheelEvent<T = Element> 滚轮事件对象
  • AnimationEvent<T = Element> 动画事件对象
  • TransitionEvent<T = Element> 过渡事件对象

Promise 类型

Promise<T> 是一个泛型类型,T 泛型变量用于确定使用 then 方法时接收的第一个回调函数(onfulfilled)的参数类型。

interface IResponse<T> {
  message: string,
  result: T,
  success: boolean,
}
async function getResponse (): Promise<IResponse<number[]>> {
  return {
    message: '获取成功',
    result: [1, 2, 3],
    success: true,
  }
}
getResponse()
  .then(response => {
    console.log(response.result)
  })

使用 react-router-dom

withRouter(ModuleLayout)

这类高阶组件的使用 方式,通常都需要继承到高阶组件 的 类型定义,如 antd Form.create 需要继承 FormComponentProps

import { FormComponentProps} from 'antd/lib/form/Form';
import { withRouter, Link, RouteComponentProps } from 'react-router-dom';
interface IProps extends RouteComponentProps<any> {
  basePath: string;
  menuList: IMenuItem[];
  children: JSX.Element;
}
function App(props: IProps){
    // 因为继承了 RouteComponentProps 所以可以获取 location
    const {location} = props;
    // xx
}
export default withRouter(ModuleLayout);

react 定义方法 useApi

/* eslint-disable no-param-reassign */
import { useRef, useEffect } from '@alipay/bigfish/react';
import { useImmer } from 'use-immer';
type Service<T> = () => Promise<T>;
type DependencyList = ReadonlyArray<any>;
interface Option<T> {
  onSuccess?: (data: T) => void;
  onError?: (errMsg: string) => void;
}
interface State {
  data: any;
  loading: boolean;
}
interface ResponseData<T> {
  success: boolean;
  data: T;
  message: string;
}
export default function useApi<T>(
  service: Service<ResponseData<T>>,
  dependencyList: DependencyList = [],
  option?: Option<T>
) {
  const initialState: State = {
    data: undefined,
    loading: false,
  };
  const [state, setState] = useImmer(initialState);
  const serviceId = useRef(0);
  useEffect(() => {
    const currentId = serviceId.current;
    setState(draft => {
      draft.loading = true;
      draft.data = null;
    });
    // 异步方法
    service().then(data => {
      // 组件卸载不更改
      if (currentId !== serviceId.current) {
        return;
      }
      if (!data.success) {
        // 错误
        setState(draft => {
          draft.loading = false;
          draft.data = null;
        });
        if (option && option.onError) {
          option.onError(data.message);
        }
      } else {
        // 成功
        setState(draft => {
          draft.loading = false;
          draft.data = data.data;
        });
        if (option && option.onSuccess) {
          option.onSuccess(data.data);
        }
      }
    });
    return () => {
      serviceId.current += 1;
    };
  }, dependencyList);
  return [state, setState];
}

react 使用 useRef

import React, { useRef, useState, FC } from '@alipay/bigfish/react';
import { message } from 'antd';
interface IProps extends FormComponentProps {
  isShow:boolean;
}
interface IUseRef extends HTMLDivElement {
  getAssets: Function;
}
const CreateStep: FC<IProps> = props => {
  const {
    form, isShow
  } = props;
  const refList = useRef<IUseRef>(null);
  const [current, setCurrent] = useState(1);
  function setNextStep() {
    const { current } = refList;
    const { getAssets } = current; // 类型“IUseRef | null”上不存在属性“getAssets”
  }
  return <div ref={refList}>xxxx</div>;
};
export default CreateStep;

上面定义泛型的时候, 这个写法会报一个错误,因为 current 开始会是空的,后面 dom 挂在之后才会获取实例。

看下 useRef 源码定义, 也就是泛型的值就是 current 的结果

interface RefObject<T> {
   readonly current: T | null;
}
function useRef<T>(initialValue: T|null): RefObject<T>;

并且 ref={ refLise } 需要传入的是 dom 元素节点,所以通过继承 HTMLDivElement 来得到 useRef 泛型。

interface IUseRef extends HTMLDivElement {
getAssets: Function;
}

所以解决的方法。

方法一: 类型断言, 但是这样的代码其实是不严警的

 const { getAssets } = current as IUseRef;

方法二: 通过 if 判断,消除 current 为 null 的时候,如果不为 null 这里的类型就必定是 IUseRef 类型,所以可以取出 getAssets

let getAssets ;
if(current && current.getAssets){
  getAssets = current.getAssets;
}