这个玩意叫做普罗米修斯,希腊神话的盗火英雄

promise只用来包装异步函数,同步的会搞乱执行顺序,生产BUG

// 如何使用
function pro(){
return new Promise(function(resolve,reject){
setTimeout(function(){
var num = parInt(Math.random()*10);
if(num>5){
resolve(num)
// 这个可以写成
// return Promise.resolve(num)
}else{
reject(num)
// 这个可以写成
// return Promise.reject(num)
}
},5000)
})
}
// pro()这个返回的是一个pending的Promise对象
// Promise可以被then启动,参数有两个,跟new的时候对应也是两个
// new的时候第一个参数传递成功,then的时候第一个参数接受成功
// new的时候第二个参数传递失败,then的时候第二个参数接受失败
pro().then((res)=>{ ... },(error)=>{ ... })

这个api是有固定写法的,用来把回调的异步函数转成链式的异步函数

先看看传统的回调型异步函数

function ajax1(){
ajax({
sucess:function(res1){
//回调ajax2,或者直接把第二个ajax写在这里面
ajax2(res1)
}
})
}
function ajax2(res1){
ajax({
sucess:function(res2){
...
}
})
}
ajax1()

Promise写法

function ajax1(){
return new Promise((resolve,reject)=>{
ajax({
sucess:function(res1){
//回调ajax2,或者直接把第二个ajax写在这里面
resolve(res1)
}
})
}
}
function ajax2(){
return new Promise((resolve,reject)=>{
ajax({
sucess:function(res2){
//回调ajax2,或者直接把第二个ajax写在这里面
resolve(res2)
}
})
}
}
ajax1().then((res1)=>{
return ajax2(res1)
}).then((res2)=>{
...
})

promise.resolve

let res = Promise.resolve("123")
res.then(res=>{ console.log(res) })

promise.reject

let res = Promise.reject("123")
res.then(res=>{ console.log(res) })

Promise.all

这个使用在几个异步函数需要同时请求但是相互不关联的情况

常用来作为初始化加载使用

Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
},(error)=> {
console.log(error)
});
// 如果上面几个promise函数没有全部返回成功,就会指向error

看了上面的写法觉得也不过如此是吧,有没有改变,代码还变多了,我也是这么觉得的,直到看到Promise配合async使用

async

这个是Generator函数的语法糖

什么是语法糖,就是更简易的使用,二次封装

什么是Generator函数,这个是es6的api,还没被人知道就被他的语法糖async给抢了头条,所以不管,知道语法糖async怎么用就行

任何函数都可以在前面加上单词async把函数升级成异步管理函数

async只能在该函数的作用域里使用,如果是函数里的函数就得再写一次async了

async要跟await配合使用,否则没有存在意义

await要连接一个promise函数,primise要是一个异步函数

这几个点不遵守肯定会有一些执行顺序等等的BUG

function ajax1(){
return new Promise((resolve,reject)=>{
ajax({
sucess:function(res1){
//回调ajax2,或者直接把第二个ajax写在这里面
resolve(res1)
}
})
}
}
function ajax2(opt){
return new Promise((resolve,reject)=>{
ajax({
sucess:function(res2){
//回调ajax2,或者直接把第二个ajax写在这里面
resolve(res2)
}
})
}
}
async function init(){
var res1 = await ajax1()
var opt = res1 + 1; //模拟正常的方法什么的
var res2 = await ajax2(opt)
}
init()

上面的代码如果是同步代码我们是很好理解的,但是因为是异步的,就不好理解了,正常来说因为ajax1和ajax2是异步的,res1和res2只会拿到undefined,这种运行顺序根本巅峰了对异步的理解,你确定这样的代码执行下来没问题?

有没有问题可以自己试试

async错误处理

// 统一处理
async function init(){
try{
var aa = await A()
var bb = await B()
}catch(err) {
console.log(err)
}
} // 单独处理
async function init(){
const [err, data] = await A().then(data => [null, data]).catch(err => [err, null])
const [err, data] = await B().then(data => [null, data]).catch(err => [err, null])
} // 上面的优化写法
// 抽离成公共方法
const awaitWrap = (promise) => {
return promise
.then(data => [null, data])
.catch(err => [err, null])
}
async function init(){
const [err, data] = await awaitWrap(A())
const [err, data] = await awaitWrap(B())
}

如何理解async呢

我们可以认为await阻塞了线程,如果有了解过java,在java里有个yeild的方法,这个方法就是await的语法糖,这个API让异步变成了同步,让代码更加的好理解

做一个网络测速

网络测速的前提是服务器超大的带宽

原理是让前端递归去获取服务器的图片获得下载的网速,再把图片转base64递归上传获得上传的网速,我做了五个实验

第一个

var index = 10;
function yi() {
var start = new Date().getTime()
var img = document.createElement("img");
var num = Math.random()
img.src = './img/xxx.png?num=' + num;
img.onload = function (res){
var end = new Date().getTime()
console.log("递归----"+(end-start))
index--;
if(index!=0){
yi()
}
}
}
yi()

第二个

var index = 10;
var promiseArr = [];
function getImg() {
return new Promise(function (resolve, reject) {
var start = new Date().getTime()
var img = document.createElement("img");
var num = Math.random()
img.src = './img/girs.png?num=' + num;
img.onload = function (res){
var end = new Date().getTime()
console.log("Promise.all----"+(end-start))
resolve(end-start);
}
})
}
function er() {
for(var i=0;i<10;i++){
promiseArr.push(getImg())
}
Promise.all(promiseArr).then()
}
er()

第三个

function getImg() {
return new Promise(function (resolve, reject) {
var start = new Date().getTime()
var img = document.createElement("img");
var num = Math.random()
img.src = './img/girs.png?num=' + num;
img.onload = function (res){
var end = new Date().getTime()
console.log("10次await-----"+(end-start))
resolve(end-start);
}
})
}
async function san() {
var allTime = 0;
allTime += await getImg();
allTime += await getImg();
allTime += await getImg();
allTime += await getImg();
allTime += await getImg();
allTime += await getImg();
allTime += await getImg();
allTime += await getImg();
allTime += await getImg();
allTime += await getImg();
}
san()

第四个

function getImg() {
return new Promise(function (resolve, reject) {
var start = new Date().getTime()
var img = document.createElement("img");
var num = Math.random()
img.src = './img/girs.png?num=' + num;
img.onload = function (res){
var end = new Date().getTime()
console.log("for(x){await x}-----"+(end-start))
resolve(end-start);
}
})
}
async function si() {
var arr = []
for(var i=0;i<10;i++){
arr.push(getImg())
}
for (const x of arr){
await x;
}
}
si()

第五个

function getImg() {
return new Promise(function (resolve, reject) {
var start = new Date().getTime()
var img = document.createElement("img");
var num = Math.random()
img.src = './img/girs.png?num=' + num;
img.onload = function (res){
var end = new Date().getTime()
console.log("for await(x){x}+-----"+(end-start))
resolve(end-start);
}
})
}
async function wu() {
var arr = []
for (var i=0;i<10;i++){
arr.push(getImg())
}
for await(const x of arr){
x;
}
}
wu()

这五个代码的执行时间都不一样,为什么还得研究

封装一个promise版本的ajax

function ajax(url, method = 'get', param = {}) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const paramString = getStringParam(param);
if (method === 'get' && paramString) {
url.indexOf('?') > -1 ? url += paramString : url += `?${paramString}`
}
xhr.open(method, url);
xhr.onload = function () {
const result = {
status: xhr.status,
statusText: xhr.statusText,
headers: xhr.getAllResponseHeaders(),
data: xhr.response || xhr.responseText
}
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
resolve(result);
} else {
reject(result);
}
}
// 设置请求头
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// 跨域携带cookie
xhr.withCredentials = true;
// 错误处理
xhr.onerror = function () {
reject(new TypeError('请求出错'));
}
xhr.timeout = function () {
reject(new TypeError('请求超时'));
}
xhr.onabort = function () {
reject(new TypeError('请求被终止'));
}
if (method === 'post') {
xhr.send(paramString);
} else {
xhr.send();
}
})
} function getStringParam(param) {
let dataString = '';
for (const key in param) {
dataString += `${key}=${param[key]}&`
}
return dataString;
}

强大的promise的更多相关文章

  1. Js中强大的Promise异步机制

    少年别激动 我的这份随笔里面只涉及promise概念 如果想深入了解Promise的用法 可以去阮老师es6入门里面详读 奉上链接 http://es6.ruanyifeng.com/#docs/pr ...

  2. ES6 之 let和const命令 Symbol Promise对象

    ECMAScript 6入门 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了. (2016年6月,发布了小幅修订的<ECMASc ...

  3. promise 进阶 —— async / await 结合 bluebird

    一.背景 1.Node.js 异步控制 在之前写的 callback vs async.js vs promise vs async / await 里,我介绍了 ES6 的 promise 和 ES ...

  4. 从如何使用到如何实现一个Promise

    前言 这篇文章我们一起来学习如何使用Promise,以及如何实现一个自己的Promise,讲解非常清楚,全程一步一步往后实现,附带详细注释与原理讲解. 如果你觉的这篇文章有帮助到你,️关注+点赞️鼓励 ...

  5. ES5-ES6-ES7_Promise对象详解

    Promise对象概述(什么是Promise) Promise 是异步编程的一种解决方案,比传统的异步解决方案——回调函数和事件——更合理和更强大 所谓Promise,简单说就是一个容器,里面保存着某 ...

  6. 多角度对比 ES5与ES6的区别

    ES5与ES6的对比不同点整理 本文关键词:ES6,javascript, 1.Default Parameters(默认参数) es6之前,定义默认参数的方法是在一个方法内部定义 var link ...

  7. vue项目开发前的es6的知识储备

    let命令 学习笔记 1.let所声明的变量,只在let命令所在的代码块内有效. 2.不存在变量提升:所声明的变量一定要在声明后使用,否则报错. 一定要先声明,再去使用.let x=x;这样就是错误的 ...

  8. ES6中比较实用的几个特性

    1.Default Parameters(默认参数) in ES6 es6之前,定义默认参数的方法是在一个方法内部定义 var link = function (height, color, url) ...

  9. 前端面试题-JavaScript

    引用GitHub 上 ltadpoles的前端面试 https://github.com/ltadpoles 目录  1. JavaScript 有哪些数据类型  2. 怎么判断不同的JS数据类型   ...

随机推荐

  1. 金币(0)<P2015_1>

    金币 (coin.cpp/c/pas) [问题描述]  国王将金币作为工资,发放给忠诚的骑士.第一天,骑士收到一枚金币:之后两天(第二天和第三天),每天收到两枚金币:之后三天(第四.五.六天),每天收 ...

  2. 从零构建以太坊(Ethereum)智能合约到项目实战——第25章 Embark FrameWork

    P109 .1-Embark Framework 开发入门篇P110 .2-Embark Framework 去中心化存储 (IPFS)

  3. 谈谈spring mvc与struts的区别

    1.Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上Spr ...

  4. StringUtils工具类中的isBlank()方法和isEmpty()方法的区别

    1.isBlank()方法 1 public static boolean isBlank(String str) { 2 int strLen; 3 if (str == null || (strL ...

  5. python学习 —— 字符画

    代码: import os from PIL import Image WIDTH = int(250) HEIGHT = int(250/2) ascii_char = list('toahkbdp ...

  6. 「JOI2019 Final」解题报告

    传送门 「JOI2019 Final」勇者比太郎 看懂题就很简单了,后缀和随便维护一下就好了,别用树状数组强加一个\(\log\)就行. 「JOI2019 Final」画展 显然可以先把所有的画框按大 ...

  7. 使用JNA替代JNI调用本地方法

    JNA全称是Java Native Access,是Sun推出的一种调用本地方法技术,比起它的同门师兄JNI,JNA大大简化了调用本地方法的过程,使用也比较方便, JNA是在JNI的基础上完善的,用青 ...

  8. C++ 类构造函数 & 析构函数

    前言: 析构函数和构造函数是一对.构造函数用于创建对象,而析构函数是用来撤销对象.简单的说:一个对象出生的时候,使用构造函数,死掉的时候,使用析构函数.构造函数 和 析构函数 各有各的用途,在构造函数 ...

  9. 四 SpringMVC与页面之间的参数传递&高级参数的绑定&日期类型的转换

    参数传递: 1 原生方式:使用Servlet  API  , request.getParameter("id"); 2 直接将请求参数作为Controller中的形参: publ ...

  10. C# DataSet与DataTable的区别和用法 ---转载

    C# DataSet与DataTable的区别和用法 转载:https://www.cnblogs.com/liuyi-li/p/6340411.html DataSet是数据集,DataTable是 ...