Here i am trying to wrap my head around promises.Here on first request i fetch a set of links.and on next request i fetch the content of first link.But i want to make a delay before returning next promise object.So i use setTimeout on it. But it gives me the following JSON error (without setTimeout() it works just fine)
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
i would like to know why it fails?
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); }); 47 Answers
To keep the promise chain going, you can't use setTimeout() the way you did because you aren't returning a promise from the .then() handler - you're returning it from the setTimeout() callback which does you no good.
Instead, you can make a simple little delay function like this:
function delay(t, v) { return new Promise(function(resolve) { setTimeout(resolve.bind(null, v), t) }); } And, then use it like this:
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"); }); }); Here you're returning a promise from the .then() handler and thus it is chained appropriately.
You can also add a delay method to the Promise object and then directly use a .delay(x) method on your promises like this:
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); });Or, use the Bluebird promise library which already has the .delay() method built-in.
.then(() => new Promise((resolve) => setTimeout(resolve, 15000))) UPDATE:
when I need sleep in async function I throw in
await new Promise(resolve => setTimeout(resolve, 1000)) 0The shorter ES6 version of the answer:
const delay = t => new Promise(resolve => setTimeout(resolve, t)); And then you can do:
delay(3000).then(() => console.log('Hello')); 2If you are inside a .then() block and you want to execute a 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!!!'); }) output will as shown below
wait for 10 seconds . . . . 10 seconds Timer expired!!! promise resolved!!! Happy Coding!
0Since node v15, you can use timers promise API
example from the doc:
import { setTimeout } from 'timers/promises' const res = await setTimeout(100, 'result') console.log(res) // Prints 'result' In node.js you can also do the following:
const { promisify } = require('util') const delay = promisify(setTimeout) delay(1000).then(() => console.log('hello')) 2const myStuff = new Promise(function (resolve) { console.log("before timeout"); setTimeout( function (x) { console.log("inside the timeout"); resolve(x); }, 3000, "after timeout" ); }).then((response) => console.log(response));