在承诺链上使用 setTimeout
Posted
技术标签:
【中文标题】在承诺链上使用 setTimeout【英文标题】:Using setTimeout on promise chain 【发布时间】:2017-01-25 02:17:00 【问题描述】:在这里,我试图将我的头绕在 Promise 上。在第一次请求时,我会获取一组链接。在下一次请求时,我会获取第一个链接的内容。但是我想在返回下一个 Promise 对象之前进行延迟。所以我在上面使用 setTimeout 。但它给了我以下 JSON 错误 (without setTimeout() it works just fine
)
SyntaxError:JSON.parse:第 1 行第 1 列出现意外字符 JSON 数据
我想知道为什么会失败?
let globalObj=;
function getLinks(url)
return new Promise(function(resolve,reject)
let http = new XMLHttpRequest();
http.onreadystatechange = function()
if(http.readyState == 4)
if(http.status == 200)
resolve(http.response);
else
reject(new Error());
http.open("GET",url,true);
http.send();
);
getLinks('links.txt').then(function(links)
let all_links = (JSON.parse(links));
globalObj=all_links;
return getLinks(globalObj["one"]+".txt");
).then(function(topic)
writeToBody(topic);
setTimeout(function()
return getLinks(globalObj["two"]+".txt"); // without setTimeout it works fine
,1000);
);
【问题讨论】:
请注意,return
是特定于函数的,并且只返回父函数,并且不能从异步方法返回。
请注意有much better ways 来构造此代码而不是使用globalObj
。
JSON.parse
扔哪里了?我很难相信一个then
回调中是否有setTimeout
会影响上一个then
回调中的调用。
这能回答你的问题吗? What is the javascript version of sleep()?
【参考方案1】:
为了保持 Promise 链继续运行,你不能像以前那样使用 setTimeout()
,因为你没有从 .then()
处理程序返回一个 Promise - 你是从 setTimeout()
回调返回它你没好处。
相反,您可以像这样制作一个简单的小延迟函数:
function delay(t, v)
return new Promise(function(resolve)
setTimeout(resolve.bind(null, v), t)
);
然后,像这样使用它:
getLinks('links.txt').then(function(links)
let all_links = (JSON.parse(links));
globalObj=all_links;
return getLinks(globalObj["one"]+".txt");
).then(function(topic)
writeToBody(topic);
// return a promise here that will be chained to prior promise
return delay(1000).then(function()
return getLinks(globalObj["two"]+".txt");
);
);
在这里,您从 .then()
处理程序返回了一个承诺,因此它被适当地链接起来。
您还可以向 Promise 对象添加延迟方法,然后直接在您的 Promise 上使用 .delay(x)
方法,如下所示:
function delay(t, v)
return new Promise(function(resolve)
setTimeout(resolve.bind(null, v), t)
);
Promise.prototype.delay = function(t)
return this.then(function(v)
return delay(t, v);
);
Promise.resolve("hello").delay(500).then(function(v)
console.log(v);
);
或者,使用已经内置.delay()
方法的Bluebird promise library。
【讨论】:
resolve 函数就是 then() 里面的函数。。所以 setTimeout(resolve,t) 的意思是 setTimeout(function() return ....,t) 是不是...那么为什么它会起作用呢? @AL-zami -delay()
返回一个将在 setTimeout()
之后解决的承诺。
我为 setTimeout 创建了一个 Promise 包装器,以便轻松地延迟一个 Promise。 github.com/zengfenfei/delay
@pdem - v
是一个可选值,您希望延迟承诺解决并因此传递承诺链。 resolve.bind(null, v)
代替 function() resolve(v);
都可以。
非常感谢...原型延迟有效,但功能无效>>> .then 语句。 t 未定义。【参考方案2】:
.then(() => new Promise((resolve) => setTimeout(resolve, 15000)))
更新:
当我需要在异步函数中休眠时,我会抛出
await new Promise(resolve => setTimeout(resolve, 1000))
【讨论】:
【参考方案3】:答案的较短 ES6 版本:
const delay = t => new Promise(resolve => setTimeout(resolve, t));
然后你可以这样做:
delay(3000).then(() => console.log('Hello'));
【讨论】:
如果你需要reject
选项,例如用于 eslint 验证,那么 const delay = ms => new Promise((resolve, reject) => setTimeout(resolve, ms))
看看如何在 Mocha 测试中使用它 - ***.com/a/70348823/1019307【参考方案4】:
如果您在 .then() 块内并且想要执行 settimeout()
.then(() =>
console.log('wait for 10 seconds . . . . ');
return new Promise(function(resolve, reject)
setTimeout(() =>
console.log('10 seconds Timer expired!!!');
resolve();
, 10000)
);
)
.then(() =>
console.log('promise resolved!!!');
)
输出如下图
wait for 10 seconds . . . .
10 seconds Timer expired!!!
promise resolved!!!
编码愉快!
【讨论】:
【参考方案5】:在 node.js 中你还可以执行以下操作:
const promisify = require('util')
const delay = promisify(setTimeout)
delay(1000).then(() => console.log('hello'))
【讨论】:
我试过这个并且得到无效的参数数量,在延迟函数中预期为 0。 我可以确认它在 node.js 8、10、12、13 中有效。不确定您是如何运行代码的,但我只能假设util
被错误地填充。你用的是打包器还是什么的?【参考方案6】:
从node v15开始,你可以使用timers promise API
文档中的示例:
import setTimeout from 'timers/promises'
const res = await setTimeout(100, 'result')
console.log(res) // Prints 'result'
【讨论】:
以上是关于在承诺链上使用 setTimeout的主要内容,如果未能解决你的问题,请参考以下文章