Coursera视频无法观看的三种不同解决方法(亲测有效) admin 2023-09-06 11:24:02 篇首语:本文由小编为大家整理,主要介绍了Coursera视频无法观看的三种不同解决方法(亲测有效)相关的知识,希望对你有一定的参考价值。 参考技术A 最近在coursera上课时出现了视频黑屏,网页缓冲,无法观看等问题,经过查询发现很多人也有同样的问题。对于不同的原因,一般来说解决方法也不同。这里有三种办法,大家可以挨个尝试,肯定有一个能用。 1. 浏览器原因 在win7和部分WIN10上用的chrome会出现黑屏现象。有两个办法: 可以换浏览器。Chrome自从22开始,在win7上的html5视频就放不了了。 将鼠标放在右上方你的名字上,等下拉菜单出现后,选择course preferences。在video player下选择flash player。2.网络原因 这种原因占了大多数,基本的方法就是改HOST 1. 用管理员权限记事本打开host文件 很多同学问hosts是啥,在哪。看下图(路径就是图片上的)2. 将如下内容复制到文件末尾 52.84.246.90 d3c33hcgiwev3.cloudfront.net 52.84.246.252 d3c33hcgiwev3.cloudfront.net 52.84.246.144 d3c33hcgiwev3.cloudfront.net 52.84.246.72 d3c33hcgiwev3.cloudfront.net 52.84.246.106 d3c33hcgiwev3.cloudfront.net 52.84.246.135 d3c33hcgiwev3.cloudfront.net 52.84.246.114 d3c33hcgiwev3.cloudfront.net 52.84.246.90 d3c33hcgiwev3.cloudfront.net 52.84.246.227 d3c33hcgiwev3.cloudfront.net 3. 打开命令行,输入如下命令 ipconfig/flushdns 最后:如果都不行 就剩最后一个办法了!如果实在懒得动手或者前面两个办法也没用,那就加速器看吧,教程和方式可以进入官网了解一下:www.ftjiasu1.com JavaScript 循环中调用异步函数的三种方法,及为什么 forEach 无法工作的分析 JavaScript 循环中调用异步函数的三种方法,及为什么 forEach 无法工作的分析 业务分析初版的问题解决方案传统的 for 循环不使用 for 循环的解决方案分析 forEach 为什么不工作并行解决方案串行解决方案 总结 本文主要分析在循环体中怎么调用异步函数,并且满足循环调用异步函数,并在异步函数值返回之后,再处理后续业务的同步需求。 这篇文章是受到和 六卿 在群里讨论问题时启发而写的,主要讨论的问题就只在循环体内进行异步调用。他也写了自己的总结: node 中循环异步的问题["解决方案"]_源于 map 循环和 for 循环对异步事件配合 async、await 的支持。 业务分析 根据我的理解,当时讨论的问题是基于这样一个需求: 首先需要调用一个 API 去获得数据 获取的数据是一个数组类型,这里就代称为 arr 会对 arr 进行遍历,在遍历的过程中继续调用其他的 API 去获得数据,并且对数据进行一些操作 整体的业务逻辑和需求,模拟大概是这个样子的: const map = new Map([ [1, "one"], [2, "two"], [3, "three"], [4, "four"], [5, "five"],]);// 用 setTimeout 模拟异步的 api 调用// timeout 会获得一个数组类型的数据,随后会有另外的 api 根据数组内的数据,再一次去进行异步调用,获取其他数据const timeout = () => new Promise((resolve) => setTimeout(() => resolve([1, 2, 3, 4, 5])), 1000);// 循环体内调用的数据const getEl = (key) => new Promise((resolve) => setTimeout(() => resolve(map.get(key)), 1000));const getData = () => { const data = timeout(); let str = []; // 这里没有处理异步操作,所以会有语法错误 data.forEach((el) => { const elVal = getEl(el); str.push(elVal); }); // 最后输出结果应该是 ["one", "two", ...] 这样一个包含 异步调用后返回值 的数组 console.log(str);};getData(); 当然,上面只是一个最基本的逻辑实现,并没有实现异步操作,现在直接运行的话就会报错。不过基本的逻辑是在这里的: API 那里获取到值 data遍历 data,在遍历中继续调用 API 取值并进行操作。 初版的问题 最初的方案其实就是比较平铺直叙,用 async/await 配合的方式去获取数据: // 其他函数没有改动,只修改了 getData 这一部分const getData = async () => { // 使用 await 语法糖 const data = await timeout(); let str = []; // 加上 async 和 await 去等待异步调用 data.forEach(async (el) => { const elVal = await getEl(el); str.push(elVal); // 可以正常输出 console.log(elVal); }); // 返回值却是一个空数组 console.log(str);};getData(); 输出结果却不尽如人意,在命令行中输出的顺序是这样的: []onetwothreefourfive 可以看到,异步的数据获取是在输出数组之后发生的,这也代表 forEach 内的异步调用的顺序,不如预期所想。 解决方案 改为 for循环体 是 六卿 在自己的总结内提出的解决方案;这里再提出了两个不使用 for循环体 的解决方案。 传统的 for 循环 一个解决方案就是将 forEach/map 替换成传统的 for (let i = 0; i < arr.lengt; i++) 这样的传统写法,如: const getData2 = async () => { const data = await timeout(); let str = []; for (let i = 0; i < data.length; i++) { const element = await getEl(data[i]); console.log(element); str.push(element); } console.log(str);};getData2(); 最终的输出结果为: onetwothreefourfive[ "one", "two", "three", "four", "five" ] 数组的输出结果在 API 调用结果之后,也就意味着数据可以正常地被渲染或是处理。 不使用 for 循环的解决方案 所以异步的代码只能使用传统的 for 循环吗? 也不尽然,只是解决方法无法基于 forEach 去实现而已。 分析 forEach 为什么不工作 在输出的时候我发现了一些微妙的异常,例如说使用 for 循环时,每一行的输出都是有一定间隔事件的——毕竟 await 应该会“锁”住运行,一直到数据接收之后才会进行下一步的调用。但是使用 forEach 函数时,它等待了大约几秒钟的时间,随后一下子将所有的结果一起输出。 直接用文字描述可能没有这么直观,那么就打几个时间戳。一个在刚刚进入函数的时候打印出当前时间,一个在循环体内输出值的时候打印出当前时间,更加直观的对比一下: forEachfor也就是说,forEach 的循环调用并没有 await 里面的异步操作。所以,当 forEach 中的同步代码执行完毕之后,异步代码才开始执行,这也是为什么 forEach 的代码先输出了一个空的数组之后,才在控制台上打印异步调用中获取的值。 异步调用的复习资料在这里:[万字详解]JavaScript 中的异步模式及 Promise 使用 那么,函数最上方已经声明了 async 关键字,forEach 中也使用了 await 去等数。而且,明明 await timeout() 工作了,为什么就只有 forEach 没有工作? 那是因为,forEach 整个函数没有使用 await 进行等待,整个 forEach 是同步执行的。forEach 的实现是基于内部的回调函数执行,因此,当进入循环之后,函数内部会去调用传进来的回调函数。当回调函数是异步时,回调函数就会被放入时间循环机制中,forEach 内部会继续去执行同步代码,也就是继续循环。 很可惜的是,基于历史原因——forEach 函数是 ES5 时代的函数,Promise 等异步操作的支持是 ES6 以后才有的支持——直接使用 forEach 是没有办法实现在循环体内调用异步函数的方法。 但是,都 2021 年了,这也不代表没有解决方案。 并行解决方案 如果数据彼此之间没有依赖关系,其实个人更建议使用这种方式,相对而言效率会更高一些。 实现的方式是 Promise.all 结合 await 和 map 去实现: Promise.all 可以接收由 Promise 组成的数组,并且返回一个 Promise。 map 的特性与 forEach 相似,区别在于前者会返回一个数组,后者会返回一个 undefined。 Promise.all 的参数正好又是一个由 Promise 组成的数组;并且,Promise.all 的返回值就是一个 Promise await 是 ES7 推出的语法糖,可以用来等待一个 Promise 的执行完成。 所以结合 Promise.all,await 和 map 就可以近似同步地发送多个异步请求。之所以说是 近似,还是因为毕竟是一个迭代,总归需要按序数组中第一个元素开始执行,只不过大多数情况下,数组的迭代与异步操作比起来消耗时间可以小到近乎不计。 实现如下: const getData = async () => { const data = await timeout(); const curr = new Date(); console.log(curr); let str = []; // 使用 Promise.all 去等待内部所有的 Promise 执行完毕 await Promise.all(data.map((el) => getEl(el))).then((val) => { str = val; console.log(new Date() - curr); return val; }); console.log(str);};getData(); 效果截图: 可以看出,与最初使用传统的 for 循环相比,使用 Promise.all 能够有效的提升性能。当有多个较为耗时的异步任务,并且彼此之间没有依赖关系的时候,为了能够提升用户体验,最好还是使用 Promise.all 去调用。 这是因为 await 等待的是所有的 Promise 执行完毕的结果,即锁住的是 Promise.all,而内部的 map 依旧是同步执行的。所以对于循环体内的异步函数来说,它不需要等待上一个迭代完成,再去执行下一个迭代——await 这个语法糖会等待 Promise 执行完毕再去执行下一个 Promise。 其执行流程大概如下: input Promise All iteration 1 iteration 2 iteration 3 ... iteration N output 串行解决方案 for await...of 是基于对 iterable(可迭代) 的实现,这种实现比较适合用于有依赖关系的内容。如较大文件的加载,可以通过在阅读到某一个点的时候触发下一段文件的加载,以达到提升用户体验感的效果。 使用案例如下: const getData3 = async () => { const data = await timeout(); const curr = new Date(); console.log(curr); let str = []; for await (el of data) { const element = await getEl(el); console.log(element, new Date() - curr); str.push(element); } console.log(str);};getData3(); 效果如下: 因为使用了 await 去等待上一个异步调用结果返回之后,再去执行下一个异步调用,因此消耗的时间也更多。 其执行流程大概如下: