在承诺链上使用 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的主要内容,如果未能解决你的问题,请参考以下文章

在solidity合约实例承诺中反应setState

链上生活猜想:一个让物物实现交换价值的中间件

如何使用代币在区块链上筹款

使用 Web3 和 Python 在 Polygon 区块链上检测新的 PairCreated 事件

科普文章|Moonriver链上数据哪里看?

在 Chrome 扩展程序中,如何确保在使用 chrome-promise 的下一个承诺之前解决上一个承诺?