Promise详解-1:初识Promise

news2024/12/22 23:09:18

最近在回顾ES6的知识,想整理下跟Promise相关的内容。我准备整一个Promise解读的系列,看看能深入到什么程度吧。由浅入深,先认识下Promise。

痛苦的回忆:回调地狱

假如现在让你维护一个“古老”的项目,缺少脚手架的加持,只能使用es5的语法来开发,我相信你一定会深刻的体会到es6添加Promise是多么伟大的行为。在es5的时代,异步编程需要依赖回调函数来实现,这就会导致一个问题:回调地狱(callback hell),代码结构会变成复杂,可读性、可维护性差到极致。例如:如果有一个业务需要连续调用三个接口,那么就需要这么写:

ajax('api1', function(res1){
  if(res1.success) {
    ajax('api2', function(res2) {
      if (res2.success) {
        ajax('api3', function(res3){
          if(res3.success) {
            // dosomething....
          }
        });
      }
    })
  }
})

如果场景更复杂的话,可能就会变成这样:

除了接口调用,事件、异步加载等等需要等待的操作基本都需要通过回调来实现。整个项目中充斥着这样的代码基本就只能靠记忆去维护。

Promise是什么?

es6的规范中新增Promise对象,是异步编程的一个解决方案。Promise相当于提供一个容器,这个容器会封装一个单独的“时间线”,这个独立的“时间线”与主线程的执行是并行,当容器内发生变化的时候,容器会更新其状态,外部可以通过API获取到状态变更的结果,并且这个状态会被固定在容器中,保持不变,无论什么时候都可以获取。

Promise对象提供了更清晰的异步操作处理,可以将异步操作封装到Promise内,通过统一的方法来处理异步操作。当包装在Promise中的异步操作有结果时,Promise对象会根据异步操作的结果(正确或是错误)更新状态,并返回结果,我们可以通过Promise的then或者catch方法来获取异步操作的结果。针对上面的多个异步串联的操作,Promise对象提供链式调用的方式,通过then方法将多个异步操作串联起来,形成一个操作序列。这种方式可以避免回调地狱,将多层嵌套变成使得代码更加清晰和易于理解。针对其他多个异步操作的场景,Promise对象还提供了一些静态方法,如Promise.all和Promise.race,用于处理多个异步操作的结果。这些功能使得Promise对象成为处理异步操作的强大工具,能够大大简化异步操作的处理流程,提高代码的可维护性和可读性。

Promise的状态

Promise通过状态来定义包裹的异步操作的目前所处的阶段,Promise提供了三个互斥的状态:fulfilled(已成功) 、rejected(已失败)、pending(进行中),任何Promise对象都处于这三种状态之一。

当我们创建一个Promise对象时,这个Promise对象处于pending状态,再异步操作产生结果后,会有以下两种状态的变化:

  • 异步操作成功:pending转换到fulfilled
  • 异步操作失败:pending转换到rejected

这个状态一旦变更,就不会再改变,而且无论是什么时候都可以获取到对应的结果。就是说在Promise对象的状态发生变化后,在任何时候都可以为Promise添加回调函数都可以会立即得到这个结果。这与事件是完全不同,在事件的模式下,如果你错过了它,就无法在获取结果。

Promise的基础用法

按照ES6的规范,Promise对象内置的Promise构造函数来实例化:

let promise = new Promise(function(resolve, reject) {
    // do sync 
    resolve(); // 将promise的状态置为fulfilled(已成功)
    reject(); // 将promise的状态置为rejected(已失败)
});

这时,我们就得到一个`Promise`对象的实例:`promise`,然后通过这个实例,可以在任何时候取得异步操作的结果:

promise.then(() => {
  // do something
}).catch((error) => {
  console.error(error);
});

通过thencatch两个方法分别捕获Promise对象中包裹的异步操作的结果和错误。

这里需要注意的是,异步操作结束后会通过resolvereject来修改实例的状态。那么这里就不一定是真正反应异步操作的实际结果,而是异步操作想要外界知道的结果。这样说可能有点绕,举个例子,在请求一个接口时,请求是一个异步动作,按照ajax工具思路,应该是根据状态码来修改状态。但是在实际操作中,接口返回200,但是内容是操作失败,虽然这里的接口是请求成功(就http请求而言),但是在业务上是失败的。一般这里也会直接处理成失败的状态而不是成功状态(这就是异步操作真正想要给外界的结果)。

先整个例子

上面是Promise的基础用法,为了更好的说明,这里我先整个例子:现在假设在某个业务系统中,所有接口的请求的返回格式都是:

{
  "errCode": 0,			// 0 成功 1 失败
	"data": [],				// 数据
  "message": ''     // 信息
}

我们通过Promise + XmlHttpRequest简单封装一个ajax方法:

function createUrlParams(data) {
  return Object.keys(data).map((v) => {
    return `${v}=${data[v]}`;
  }).join('&');
}

function ajax(url = '',  data = {}, type = 'GET') {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        
        type = type.toUpperCase();

        if (type === 'GET') {
            url += '?' + createUrlParams(data);
            data = null;
        }

        xhr.open(type, url, true);
        
        xhr.onload = function() {
            if (xhr.status >= 200 && xhr.status < 300) {
                let res = JSON.parse(xhr.response);
                if (res.errCode !== 0) {
                    reject({status:'error', result: res});
                } else {
                    resolve({status:'success', result: res})
                }
              } else {
                reject(`请求失败:${xhr.status}`);
              }
        }

        xhr.onerror = function () {
            reject(`请求失败:${xhr.status}`);
        };

        xhr.send(data);
    });
}

上面的ajax方法最终会返回一个Promise实例,在请求完成的时候根据请求的状态和结果修改Promise的状态。例如获取用户的列表可以这么写:

ajax('http://xxxx.com/user/get-list')
.then(res => {
    console.log(res);
}).catch(err => {
    console.error(err);
});

基础方法说明

then方法

上面讲到我们可以通过then方法来获取异步的成功的结果,但其实then方法是接收两个回调方法,如果Promise状态为fulfilled则执行第一个回调方法,失败则执行第二个:

ajax('http://xxxx.com/user/get-list')
  .then(
    () => {
      console.log('success');
  	},
    () => {
      console.log('error');
  	}
  );

不管成功还是失败,then都会返回一个新的promise:

我们先修改下上面的代码,以便更好的观察:

const pAjax = ajax('http://xxxx.com/user/get-list');
const p1 = pAjax.then(
    () => {
      console.log('success');
    },
    () => {
      console.log('error');
    }
);

如果没有特殊操作(这个等会讲),不管成功失败,这个新的promise的状态会被置为fulfilled:

const p2 = p1.then(() => {
    console.log('success 2');
});

从上面的例子可以看出,在then的回调函数中我们并没有返回任何东西,但是then依然会返回一个promise。

例如这样:

const p2 = p1.then()
  	.then(() => {
      console.log('success');
    });

这是then的机制,如果回调函数中没有return的话,则会默认返回一个成功的promise,如果回调函数中有return,则会判断return是否为一个promise,如果不是promise,则会将其包装成promise返回,并且状态为成功。如果是promise,则直接返回,链式调用后面的方法会根据这个promise的状态触发对应的回调函数。

返回非promise

const p1 = pAjax.then(
    () => {
      return {result: 'success'};
    },
    () => {
      return {result: 'error'};
    }
);

const p2 = p1.then((res) => {
    console.log(res);
});

返回promise

可以看到,如果then中返回的是promise,链式后面的函数会等待这个promise的状态变更,再根据promise的状态来执行对应的回调。

状态传递

从上面的例子也可以看到,then主要是受到上一个promise的影响,在pAjax错误的时候,p1会触发错误回调,而p2触发的时候成功的回调。那么如果p1没有捕获错误的话,错误会在p2被捕获到吗?

const p1 = pAjax.then(
    () => {
      console.log('success');
    }
);

const p2 = p1.then(
  () => {
    console.log('success');
  }, 
  () => {
    console.log('error');
  }
)

可以看到,p2捕获到错误,说明错误是会向下传递的。

总结

then函数支持传入两个回调方法,分别为成功的回调和失败的回调,then会根据回调函数的返回值返回一个新的promise,如果返回值不是promise,封装成promise返回,如果是promise则直接返回。如果then没有捕获错误,则会将错误向下传递,这是新的promise的状态为失败。

catch方法

catch方法其实是then(null/undefined, reject())的变相写法,在指定发生错误的时候执行回调函数。

const pAjax = ajax('http://xxxx.com/user/get-list');
const p1 = pAjax.then(() => {
      console.log('success');
    }).catch((err) => {
      console.log(err);
		});

因为catchthen捕获错误的变相写法,所以then具备的特性catch都具备,这里就不多赘述了。

值得一提的是,跟传统的try/catch不一样,在promise中产生的错误,只能在promise的链路上捕获到,不会扩散到外部:

function err() {
    throw new Error('error');
}

try {
	err(); // 抛出错误
  console.log('next'); // 不执行,被错误阻塞
} catch(err) {
  console.log(err); // error对象
}
try {
   promise = ajax('http://xxxx.com/user/get-list'); // 抛出错误
  setTimeout(() => {console.log('next');}, 5000); // 5s后仍执行
} catch(err) {
  console.log(err); // 无法捕获到错误
}

另外,如果在promise中抛出错误,但是没有执行reject方法,promise还是会将状态处理成rejected

function err(){
  return new Promise((resolve, reject) => {
    throw new Error('promise error');
  });
}

err().catch(err => {
  console.log(err);   // Error: promise error
});

但是,如果已经修改了promise的状态,再抛出错误,则是无效的:

function err(){
  return new Promise((resolve, reject) => {
    resolve('success');
    throw new Error('promise error'); // 无效
  });
}

err().then((res) => {
  console.log(res); // success
}).catch(err => {
  console.log(err);   // 无
});

需要注意的,如果已经使用catch捕获了错误,那么错误就不会在向下传递,除非前面的catch将错误重新抛出。

ajax('http://xxxx.com/user/get-list')
	.catch(err => {
      console.log(err); // error信息
  }).catch(err => {
    console.log(err); // undefined
  });
 ajax('http://xxxx.com/user/get-list')
	.catch(err => {
      throw err; // 也可以写成return Promise.reject(err); 
  }).catch(err => {
    console.log(err); // error信息
  });
编写建议

前面讲到,promise的链路上错误是会向下传递的,所以呢,我建议promise的写法是按照需要在指定位置使用 catch捕获错误,不要再then中使用rejected的回调去捕获错误,这样整体的可读性更高:

ajax('http://xxxx.com/user/get-list')
  .then(() => {
    // 步骤1
  })
  .then(() => {
    // 步骤2
  }) // ...
  .catch((err) => {
    console.log(err);
  });

这样看起来更像同步的写法,更清晰可读性更高。

如果是多个promise嵌套调用的话,建议只在最外层捕获错误,这样可以在统一的地方处理错误,埋日志,错误调试等操作都会简化。当然如果不希望中间某些操作的错误终端整个promise,可以在这些操作上添加catch拦截掉错误。

这里假设是一个添加用户的场景,有几个步骤:

  1. 获取录入的用户名(正常是同步的,这里假设是一个promise)
  2. 调用接口校验用户名是否重复
  3. 提交用户名
  4. 刷新用户列表
function getForm()
  	.then(() => {
    }){
  return form();
}

function ApiCheckName(name) {
  return ajax('http://xxxx.com/user/check-name', {name})
    .then(isExists => {
      if (isExists) {
        throw new Error('用户名已存在');
      } else {
        return true;
      }
    })
}

function ApiAddUser(data) {
  return ApiCheckName(data.name)
    .then(() => {
        return ajax('http://xxxx.com/user/add', data, 'POST');
    });
}

function ApiGetUserList() {
  return ajax('http://xxxx.com/user/get-list');
}

// 封装添加用户的方法
function addUser() {
  return getForm()
    .then((form) => {
        return ApiAddUser({name: 'skkk'});
    })
    .then(() => {
      return getUserList();
    });
}

// 外部调用
addUser()
.catch((err) => {
  console.log('失败', err);
})

finally方法

finally方法是在ES2018规范引入的,所以在一些版本较低的浏览器是不支持的。finally方法是不管promise最终是成功还是失败,都会执行该方法。

ajax('http://xxxx.com/user/get-list')
	.then(() => {console.log('success');})
	.catch(() => {console.log('error');})
  .finally(() => {console.log('finally');})

如上面的代码,无论接口请求是否成功,都会执行finally

finally本质上还是then的变种,其实现的效果等于与在then的成功失败回调中分别添加相同的代码:

ajax('http://xxxx.com/user/get-list').finally(() => {
  dosomething();
});

等同于:

ajax('http://xxxx.com/user/get-list').then(
  () => {
    dosomething();
  }, 
  () => {
    dosomething();
  }
)

明显finally更简洁。

then不同的是finally是不接收参数的。

ajax('http://xxxx.com/user/get-list')
	.then(() => { return 1;})
	.catch(() => { return 2; })
  .finally((res) => {console.log(res);})  // undefined

这样我们无法通过传参来判断promise最终的状态,从而进行一些针对的操作。但是还是可以用不过来做一些终结操作。例如:实现一个带进度条的下载功能,不管下载成功或失败都要关闭重置进度条,就可以在finally中实现。

同样的,finally也是返回一个promise

const pAjax = ajax('http://xxxx.com/user/get-list');
const p1 = pAjax.then(() => { return 1;})
	.catch(() => { return 2; });
const p2 = p1.finally(res => {console.log(res);});
const p3 = p2.then(res => {console.log(res);});

可以看到返回值会越过finally传递。

同样,状态也是会向下传递的

const pAjax = ajax('http://xxxx.com/user/get-list');
console.log('pAjax ====>', pAjax);
const p1 = pAjax.finally(res => {console.log(res);});
console.log('p1 ====>', p1);
const p2 = p1.then(
    () => {console.log('success');},
    () => {console.log('error');}
);
console.log('p2 ====>', p2);

除了不接收参数,finally里返回的参数或成功的promise都也不会被传递下去:

const pAjax = ajax('http://localhost:3010');
const p1 = pAjax.finally(() => {
    return 'finally';
});
const p2 = p1.then(
    (res) => {console.log('p2 res', res);},
    (res) => {console.log('p2 res', res);}
);
const p3 = pAjax.finally(() => {
    return Promise.resolve('finally');
});
const p4 = p3.then(
    (res) => {console.log('p4 res', res);},
    (res) => {console.log('p4 res', res);}
);

p2p4都获取到pAjax的结果。

但是如果finally返回了Promise或抛出错误就会向下传递:

const p1 = pAjax.finally(() => {
    throw new Error('finally error');  // 抛出错误
});
const p2 = p1.then(
    (res) => {console.log('p2 res',res);},
    (res) => {console.log('p2 res',res);}
);
const p3 = pAjax.finally(() => {
    throw Promise.reject('finally');  // 返回成功的promise
});
const p4 = p3.then(
    (res) => {console.log('p4 res',res);},
    (res) => {console.log('p4 res',res);}
);

可以看到,无论pAjax是否成功的,但是p2p4都是捕获到p1p3抛出的错误。

当然,实际的开发中千万别这么写,finally就做一些统一的终结操作就行了。如果统一操作也是promise的话,建议单独处理。

Promise.resolve() & Promise.reject()

如果想要返回一个promise,但又不想使用new Promise的方式来实现,就可以使用这两个方法。基本上其功能与字面意义一致,Promise.resolve()会直接返回一个状态为fulfilled的promise,Promise.reject()则返回一个状态为rejected的promise。

Promise.resolve

上面说的是基本功能,不带任何参数会返回一个成功的promise。但是resolve方法可以接受一个参数,其会根据这个参数的不同返回不同的promise。

  1. 传入promise实例

传入promise实例,会直接返回这个实例,不做任何修改。

const p = Promise.resolve(ajax('http://xxxx.com/user/get-list'));
p.then(res => {
    console.log(res);  // {status: 'success', result: {…}}
}); 
  1. 传入thenable对象

thenable对象就是带then方法的对象,像这样的:

{
  then: function(resolve, reject){
    setTimeout(() => {
    	resolve('then');
    }, 500);
  }
}

将这样的对象传给Promise.resolve(),它会将其转换为promise对象,并立刻执行then函数。像这样:

const p = Promise.resolve({
    then(resolve, reject) {
        setTimeout(() => {
            resolve('thenable');
        }, 500);
    }
});
p.then(res => {
    console.log(res);   // thenable
});

then没有resolve或reject,只是一个方法甚至不是一个方法会是什么情况呢?

const p1 = Promise.resolve({
    then() {
        console.log('then function');
        return 'then';
    }
});
p1.then(res => {
    console.log('p1', res); 
});

const p2 = Promise.resolve({
    then: {
        a: 1
    }
});
p2.then(res => {
    console.log('p2', res); 
});

const p3 = Promise.resolve({
    then: '1'
});
p3.then(res => {
    console.log('p3', res); 
});

可以看到,如果then方法没有修改promise的状态的话,then方法会被执行,但是返回的promise会处于pending的状态。而then是非方法的话,会返回一个fulfilled的promise,对象被当做返回值返回。

  1. 其他类型的参数

传入对象、数组、字符串、数字等非方法类的参数,Promise.resolve会立即返回一个fulfilled的promise,并且将参数作为返回值。

Promise.resolve([1,2,3])
	.then(res => {
    console.log(res); // [1,2,3]
  })

传入的参数是一个非promise的方法,会获取该方法的返回值(如果有)做为返回值,同样也是返回一个状态为

fulfilled的promise。

function p1() {
    console.log('function p1'); // function p1
    return 'p1';
}

Promise.resolve(p1())
	.then(res => {
    console.log(res); // p1
  })

function p2() {
    console.log('function p2'); // function p2
}

Promise.resolve(p2())
	.then(res => {
    console.log(res); // undefined
  })

如果在方法中抛出错误呢?会不会走到catch呢?

function p1() {
    throw new Error('p1 error');
}

Promise.resolve(p1())
	.then(res => {
    console.log(res);
  }).catch(err => {
    console.log(err);
  });

答案是啥都没执行,因为p1在执行是就抛出错误了,后续代码终止执行。

Promise.reject

reject无论传不传入都是返回一个状态为rejected的promise。传入的任何参数都会做为失败的理由返回。

// 传入对象
Promise.reject({name: 'reject'})
	.catch(err => {
      console.log('object', err); // object {name: 'reject'}
  });
// 传入字符串
Promise.reject('reject')
	.catch(err => {
      console.log('string', err); // string reject
  });

function p1() {
    console.log('function p1');  // function p1
    return 'p1';
}

// 有返回值的方法
Promise.reject(p1())
	.catch(err => {
      console.log('p1', err); // p1 p1
  });

function p2() {
    console.log('function p2'); // function p2
}

// 无返回值的方法
Promise.reject(p2())
	.catch(err => {
      console.log('p2', err); // p2 undefined
  });

// promise
Promise.reject(ajax('http://xxxx.com/user/get-list'))
	.catch(err => {
      console.log('ajax', err);  // ajax promise
  });

这里跟resolve不一样的是,传入的参数是promise,也会将promise实例理由返回。而不是返回promise实例的结果。

总结

本文介绍了Promise最基础的知识,了解了Promise的基础应用。接下会继续深入了解Promise,敬请期待吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2257782.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【css】基础(一)

本专栏内容为&#xff1a;前端专栏 记录学习前端&#xff0c;分为若干个子专栏&#xff0c;html js css vue等 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;css专栏 &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &a…

共享GitLab中CICD自动生成的软件包

0 Preface/Foreword 1 分享软件包地址 为了方便给接收对象方便下载固件&#xff0c;在下载固件时候&#xff0c;而无需打开网页&#xff0c;直接输入地址&#xff0c;弹出的对话框是将固件另存为。 或者进入CICD页面&#xff0c;找到job&#xff0c;在Download的标签上单击右键…

【云贝教育Linux技术文章】CentOS停止维护后如何获取redhat 8.0 yum源?详细操作指南!

本文为云贝教育 刘老师 原创&#xff0c;请尊重知识产权&#xff0c;转发请注明出处&#xff0c;不接受任何抄袭、演绎和未经注明出处的转载。 众所周知&#xff0c;centos 7 在2024年6月30日&#xff0c;生命周期结束&#xff0c;官方不再进行支持维护&#xff0c;而很多环境一…

泷羽sec学习打卡-brupsuite5

声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都 与本人无关,切莫逾越法律红线,否则后果自负 关于brupsuite的那些事儿-web抓包和app抓包 常见的抓包工具有哪些&#xff1f;web抓包app抓包Android抓…

Nanolog起步笔记-9-log解压过程(3)寻找meta续

Nanolog起步笔记-9-log解压过程-3-寻找meta续 当前的目标新的改变decompressNextLogStatementmetadata查看业务面的log语句注释掉 runBenchmark();改过之后&#xff0c;2条记录之后&#xff0c;这里就直接返回了 小结 当前的目标 没有办法&#xff0c;还要继续。 当前的目标&a…

Flask使用长连接(Connection会失效)、http的keep-alive、webSocket。---GPU的CUDA会内存不足报错

Flask Curl命令返回状态Connection: close转keep-alive的方法 使用waitress-serve启动 waitress-serve --listen0.0.0.0:6002 manage:app 使用Gunicorn命令启动 gunicorn -t 1000 -w 2 -b 0.0.0.0:6002 --worker-class gevent --limit-request-line 8190 manage:appFlask使用f…

用友U8+ API接口使用教程

前言 U8和其他的公开的开放API接口有一些差异&#xff0c;他是需要先对接的到代理服务器&#xff0c;通过代理服务器进行对接&#xff0c;所以只要保证U8能上网就能对接&#xff0c;和畅捷通T的模式有点类似 流程&#xff1a; 注册成为开发者&#xff08;用于创建用友U8 API应…

xtu oj 1618 素数个数

文章目录 前言代码思路 前言 有点儿难&#xff0c;至少对我来说。去年考试我没写出来。 代码 #include<stdio.h> #include<stdbool.h> #include<stdlib.h>//加 math 那个头文件好像要加这个头文件&#xff0c;我之前编译错误过&#xff0c;血泪教训 #incl…

DAY3 构造函数

构造函数使用代码&#xff1a; #include <iostream> using namespace std; class Rec {const int length;int width; public:Rec():length(10){cout << "Rec无参构造函数" << endl;};Rec(int a,int b):length(a),width(b){cout << "Re…

分布式搜索引擎之elasticsearch基本使用2

分布式搜索引擎之elasticsearch基本使用2 在分布式搜索引擎之elasticsearch基本使用1中&#xff0c;我们已经导入了大量数据到elasticsearch中&#xff0c;实现了elasticsearch的数据存储功能。但elasticsearch最擅长的还是搜索和数据分析。 所以j接下来&#xff0c;我们研究下…

javaScript交互补充

1、元素的三大系列 1.1、offset系列 1.1.1、offset初相识 使用offset系列相关属性可以动态的得到该元素的位置&#xff08;偏移&#xff09;、大小等 ●获得元素距离带有定位祖先元素的位置 ●获得元素自身的大小&#xff08;宽度高度&#xff09; ●注意&#xff1a;返回的…

【49】AndroidStudio构建其他人开发的Android项目

(1)做Android软件开发&#xff0c;通常会看一些其他人开发的项目源码&#xff0c;当将这些项目的源码通过git clone到本地之后&#xff0c;用AndroidStudio进行打开时&#xff0c;通常会遇到一些环境配置的问题。本文即用来记录在构建他人开发项目源代码这一过程中遇到的一些常…

LLama系列模型简要概述

LLama-1&#xff08;7B, 13B, 33B, 65B参数量&#xff1b;1.4T tokens训练数据量&#xff09; 要做真正Open的AI Efficient&#xff1a;同等预算下&#xff0c;增大训练数据&#xff0c;比增大模型参数量&#xff0c;效果要更好 训练数据&#xff1a; 书、Wiki这种量少、质量高…

22. Three.js案例-创建旋转的圆环面

22. Three.js案例-创建旋转的圆环面 实现效果 知识点 WebGLRenderer (WebGL渲染器) THREE.WebGLRenderer 是Three.js中最常用的渲染器&#xff0c;用于将场景渲染到WebGL画布上。 构造器 new THREE.WebGLRenderer(parameters) 参数类型描述parametersObject可选参数对象&…

Burp(5)web网页端抓包与app渗透测试

声明&#xff01; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&…

bsp是板级支持包

里面有很多的针对该型号的板子的函数&#xff0c;可以直接调用&#xff0c;也可以直接在里面。 也可以在vivado的sdk上&#xff0c;看到很多相关文档和寄存器偏移等等。

基于智能合约的医院凭证共享中心路径探析

一、引言 随着医疗行业的不断发展和信息技术的进步&#xff0c;基于智能合约的医疗凭证共享中心解决方案成为了可能。在当今数字化时代&#xff0c;医疗领域面临着诸多挑战&#xff0c;如医疗数据的分散存储、信息共享的不便捷以及凭证管理的复杂性等问题。而智能合约的出现&am…

实验14 RNN的记忆能力和梯度爆炸实验

一 循环神经网络的记忆能力 1.数据集构建 创建了一个DigitSumDataset 类&#xff0c;包括初始化函数init、数据生成函数 generate_data、数据加载函数 load_data、__len__ 方法、__getitem__ 方法。 init函数&#xff1a;接受的参数是data_path&#xff08; 存放数据集的目录…

一文说清flink从编码到部署上线

引言&#xff1a;目前flink的文章比较多&#xff0c;但一般都关注某一特定方面&#xff0c;很少有一个文章&#xff0c;从一个简单的例子入手&#xff0c;说清楚从编码、构建、部署全流程是怎么样的。所以编写本文&#xff0c;自己做个记录备查同时跟大家分享一下。本文以简单的…

IEEE T-RO 软体机器人手指状态估计实现两栖触觉传感

摘要&#xff1a;南方科技大学戴建生院士、林间院士、万芳老师、宋超阳老师团队近期在IEEE T-RO上发表了关于软体机器人手指在两栖环境中本体感知方法的论文。 近日&#xff0c;南方科技大学戴建生院士、林间院士、万芳老师、宋超阳老师团队在机器人顶刊IEEE T-RO上以《Propri…