有个需求,某个异步请求函数可能被多次调用,重复调用消耗资源,需要对其进行优化
-
每次调用该函数都能取到返回值
-
只发送一次异步请求
这个
和节流、防抖功能不一样
,节流防抖会丢弃掉中间的请求,中间的请求获取不到返回值,这里要求每一个函数调用都能取到返回值。
很容易想到使用
同步非阻塞
方案,在第一个点击时,进入loading状态,之后的点击判断loading就等50毫秒继续检查loading的值,直到loading为false,返回localEnv。这里使用setTimeout来模拟异步请求。
<
input
onclick
=
"
clickMe()
"
type
=
"
button
"
value
=
"
点我
"
>
</
body
>
async function clickMe() {
const env = await getEnv()
console.log(env)
let localEnv
let loading = false
async function getEnv() {
if (localEnv) {
return localEnv
if (loading) {
while(loading) {
await wait(50)
return localEnv
} else {
loading = true
return new Promise((resolve, reject) => {
console.log('questing env......')
setTimeout(() => {
localEnv = {
platform: '141001',
appid: 'aoshdakhpa8fkdng'
loading = false
resolve(localEnv)
}, 2000)
function wait (time) {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, time)
方案一主要由于循环去检测loading的状态,导致不那么高效
Java中可以通过锁机制,使用wait/notify轻易实现该功能。JavaScript也可以利用锁机制来实现类似wait/notify的功能。
JavaScript可以通过resolve/reject函数来实现锁,在没有调用resolve/reject函数时,promise会看起来相当于一直阻塞(其实和Java的阻塞不一样,这里只是没有执行后续的函数)。
<input onclick="clickMe()" type="button" value="点我">
</body>
async function clickMe() {
const env = await getEnv()
console.log(env)
let localEnv, p
const queue = []
let loading = false
async function getEnv() {
return new Promise((resolve, reject) => {
if (localEnv) {
resolve(localEnv)
if (loading) {
queue.push({resolve, reject})
if (!loading && !localEnv) {
loading = true
console.log('questing env......')
setTimeout(() => {
localEnv = {
platform: '141001',
appid: 'aoshdakhpa8fkdng'
loading = false
resolve(localEnv)
while (p = queue.shift()) {
p.resolve(localEnv)
}, 2000)
利用好Promise没有resolve/reject会一直阻塞的特性,可以实现类似Java的wait/notify功能,实现同一时间多次异步请求函数都取到返回值,只触发一次异步请求的功能。
一次提交,发起多次请求的问题,很可能因为是因为在执行提交的时候,是通过触发一个脚本方法实现的。而脚本方法又是通过JQ来选中表单控件,如果页面中有多个表单,而多个表单控件都被JQ选择器选中,那么就会出现一次提交发起多次请求的问题。
当然了这只是其中一个可能的原因,可以参考一下。
Angular.js的一组异步锁定模式
此自述文件包含基本用法示例和有关完整API的详细信息,包括方法,属性和帮助程序功能。 要使用库,包括dist/async-lock.js或dist/async-lock.min.js在angular.js后您的index.html文件。
异步锁定组件:
所有组件都包含在boriskozo.async-locks angular.js模块中。
AsyncLockFactory允许您创建异步锁。
AsyncLockService环绕AsyncLockFactory环绕以提供对锁的管理。
为什么在单线程环境中需要异步锁?
当您JavaScript代码以单线程方式运行时(即,只有一个线程在同一上下文中运行每个函数),而整个代码则在多线程环境中运行。 考虑一个从服务器获取一些数据,将其更新并将其保存回服务器的函数。 您的代码如下
在前端页面开发的过程中,经常使用到Ajax请求,异步提交表单数据,或者异步刷新页面。
一般来说,使用Jquery中的$.ajax,$.post,$.getJSON,非常方便,但是有的时候,我们只需要ajax功能,这样引入Jquery比较不划算。
所以接下来便用原生JavaScrpit实现一个简单的Ajax请求,并说明ajax请求中的跨域访问问题,以及多个ajax请求的数据同步问题。
JavaScript实现Ajax异步请求
简单的ajax请求实现
Ajax请求的原理是创建一个XMLHttpRequest对象,使用这个对象来进行异步发送请求,具体实现参考下面代码:
function ajax(
问题描述:
最近,在uniapp上实现一个页面功能,需要在onReady之后获取canvasContext进行绘制,但是里面用到的一些参数,需要在onLoad上进行传参拿到,由于不同的手机,渲染速度不同,因此导致 onReady 与 onLoad 的执行先后顺序不确定,从而影响到后面的功能操作。
解决方案:
在后端,我们会想到直接使用锁来解决这个问题。但在JavaScript里面,是没有多线程的,因此也就不存在锁。在这里,我使用Promise实现锁。
Lock.js
问题:在弹窗中有个按钮,点击上线,会在列表中添加一条数据,然后弹窗消失。现在在点击按钮时,由于点击过快,在点击上线按钮到弹窗消失期间,导致请求了多次数据,造成了在列表多出了几次同一时间的信息。希望在上线按钮到弹窗消失期间,只请求一次。
解决方法一:使用this.$nextTick(),nextTick(),是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数,
在弹窗组件中的data定义一个flag,表示请求状态
data() {
最近项目总结,如果一个输入框和一个搜索按钮,点击查询的时候,需要发起请求获取数据,因为请求是异步的,则无法获取哪一次的请求是最后一次的请求,则可以进行一下操作优化:
思路一:请求外部存在一个变量,记录每次请求的标记值;可以将外部的标记值传入调用请求的内部,因为函数有作用域的概念,所以暂时目前传入的数据是会一直存在于该作用域内部的,但是外部的标记值会一直变化,当是最后一次请求的时候,外部的值和内部接收的值是相同的,可以在此处进行数据处理。
vue代码如下:
<template>
闭包两个特性:1、访问外部函数;2、维持作用域。
维持作用与主要体现在外部函数调用完毕后,其中变量赋值内部函数
在调用变量时可访问内部函数及其调用的内部函数访问的外部变量。
代码如下:
var global;
function out() {
var value = 1;
function inner() {
return value;
global = inner;
out();
global() // re
var that = this;
var myClassData = this.data.myData;
if (!(myClassData[id] && myClassData[id].length)){//限制只请求一次,当有数据时候就不发起请求了
wx....