指点成金-最美分享吧

登录

Coursera视频无法观看的三种不同解决方法(亲测有效)

佚名 举报

篇首语:本文由小编为大家整理,主要介绍了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 的支持。

业务分析

根据我的理解,当时讨论的问题是基于这样一个需求:

  1. 首先需要调用一个 API 去获得数据

    获取的数据是一个数组类型,这里就代称为 arr

  2. 会对 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();

当然,上面只是一个最基本的逻辑实现,并没有实现异步操作,现在直接运行的话就会报错。不过基本的逻辑是在这里的:

  1. API 那里获取到值 data
  2. 遍历 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 结合 awaitmap 去实现:

  • Promise.all 可以接收由 Promise 组成的数组,并且返回一个 Promise。

  • map 的特性与 forEach 相似,区别在于前者会返回一个数组,后者会返回一个 undefined。

    Promise.all 的参数正好又是一个由 Promise 组成的数组;并且,Promise.all 的返回值就是一个 Promise

  • await 是 ES7 推出的语法糖,可以用来等待一个 Promise 的执行完成。

所以结合 Promise.allawaitmap 就可以近似同步地发送多个异步请求。之所以说是 近似,还是因为毕竟是一个迭代,总归需要按序数组中第一个元素开始执行,只不过大多数情况下,数组的迭代与异步操作比起来消耗时间可以小到近乎不计。

实现如下:

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 去等待上一个异步调用结果返回之后,再去执行下一个异步调用,因此消耗的时间也更多。

其执行流程大概如下:

以上是关于Coursera视频无法观看的三种不同解决方法(亲测有效)的主要内容,如果未能解决你的问题,请参考以下文章