5

I'm not a full-time Javascript developer. We have a web app and one piece is to write out a small informational widget onto another domain. This literally is just a html table with some values written out into it. I have had to do this a couple of times over the past 8 years and I always end up doing it via a script that just document.write's out the table.

For example:

document.write('<table border="1"><tr><td>here is some content</td></tr></table>');

on theirdomain.com

<body>
....
<script src='http://ourdomain.com/arc/v1/api/inventory/1' type='text/javascript'></script>
.....
</body>

I always think this is a bit ugly but it works fine and we always have control over the content (or a trusted representative has control such as like your current inventory or something). So another project like this came up and I coded it up in like 5 minutes using document.write. Somebody else thinks this is just too ugly but I don't see what the problem is. Re the widget aspect, I have also done iframe and jsonp implementations but iframe tends not to play well with other site's css and jsonp tends to just be too much. Is there a some security element I'm missing? Or is what I'm doing ok? What would be the strongest argument against using this technique? Is there a best practice I don't get?

timpone
  • 19,235
  • 36
  • 121
  • 211
  • performance, no-js, and seo are the main gripes. some just don't like it for what seems to be personal reasons... – dandavis Jan 16 '14 at 22:01
  • 1
    It simply will crash horribly if your remote script is not synchronously loaded. Requiring that will be an issue when redesigning the including page. – Bergi Jan 16 '14 at 22:03
  • 1
    @Bergi crash? or just not render? Can totally live with that too since that would be same with a jsonp or iframe sol'n – timpone Jan 16 '14 at 22:04
  • @bergi: that's true. an innerHTML option would be better, but philosophically they are the same concept. then again, by the time you hard-code an id or url into the remote script, and take care of old IE, it loses a lot of simplicity... – dandavis Jan 16 '14 at 22:04
  • @dandavis thx Dan and Bergi, I should have put more of reqs. Would not want a jQuery sol'n (was thinking of doing load or something). There wouldn't be any further interaction with the dom at that point. – timpone Jan 16 '14 at 22:10
  • @timpone: Crash - to cite josh3736: "*the DOM will be blown away*" (see his excellent answer for details). Design your script so that you can easily change the output method, it's likely to be necessary in the future. So don't spread `document.write` calls over the script, but append to a "buffer" string and call write once in the end. – Bergi Jan 16 '14 at 22:51
  • thx @Bergi - we will have a bit of a concatenated string but hopefully won't be terrible. Looking into whether we should use the async method now. – timpone Jan 16 '14 at 23:06
  • just as an aside looking into SEO, I ran across this article suggesting that this strategy should be fine for indexing: http://moz.com/ugc/can-google-really-access-content-in-javascript-really – timpone Jan 17 '14 at 04:45

3 Answers3

4

To be honest, I don't really see a problem. Yes, document.write is very old-school, but it is simple and universally supported; you can depend on it working the same in every browser.

For your application (writing out a HTML table with some data), I don't think a more complex solution is necessary if you're willing to assume a few small risks. Dealing with DOM mutation that works correctly across browsers is not an easy thing to get right if you're not using jQuery (et al).

The risks of document.write:

  • Your script must be loaded synchronously. This means a normal inline script tag (like you're already using). However, if someone gets clever and adds the async or defer attributes to your script tag (or does something fancy like appending a dynamically created script element to the head), your script will be loaded asynchronously.

    This means that when your script eventually loads and calls write, the main document may have already finished loading and the document is "closed". Calling write on a closed document implicitly calls open, which completely clears the DOM – it's esentially the same as wiping the page clean and starting from scratch. You don't want that.

  • Because your script is loaded synchronously, you put third-party pages at the mercy of your server. If your server goes down or gets overloaded and responds slowly, every page that contain your script tag cannot finish loading until your server does respond or the browser times out the request.

    The people who put your widget on their website will not be happy.

If you're confident in your uptime, then there's really no reason to change what you're doing.

The alternative is to load your script asynchronously and insert your table into the correct spot in the DOM. This means third parties would have to both insert a script snippet (either <script async src="..."> or use the dynamic script tag insertion trick. They would also need to carve out a special <div id="tablegoeshere"> for you to put your table into.

Community
  • 1
  • 1
josh3736
  • 139,160
  • 33
  • 216
  • 263
  • thx for answer @josh3736 - re the concern about write (the second paragraph in your first bullet point). The way I have it currently constructed, would this be an issue? What if we assume our server returns in 300ms and the remainder of the page loads in 10ms (ie that the remote document.write starts 290ms after completion) - would this cause the main page to be blown away. I haven't seen this in practice but this would obviously be my largest concern. – timpone Jan 16 '14 at 23:05
  • Re second point, I agree that's a legitimate concern but would be true of any remotely loaded data or is there something specific to this implementation that makes it particuarily fragile. The script async suggestion sounds really solid. Let me look into that more - is that what you'd sugggest? I really appreciate answer. – timpone Jan 16 '14 at 23:05
  • @timpone: The whole point is that as your code is now, it is loaded and executed *synchronously*. The browser stops doing anything else until your script loads, so it doesn't matter if your server responds in 300ms or a full minute. Re #2, this is a property unique to the ` – josh3736 Jan 16 '14 at 23:17
  • thx for clarification. I just wanted to be sure I was understanding you correctly. – timpone Jan 16 '14 at 23:20
2

Using document.write() after loading the entire DOM do not allow you to access DOM any further.

See Why do I need to use document.write instead of DOM manipulation methods?.

You are in that case putting away a very powerfull functionnality of in web page...

Community
  • 1
  • 1
cubitouch
  • 1,929
  • 15
  • 28
  • 1
    This doesn't make sense. When `document.write()` called on an *open* document (one that hasn't been completely loaded yet, ie when called from a synchronous ` – josh3736 Jan 16 '14 at 22:10
  • This is effectively working on this JSFiddle (http://jsfiddle.net/2Z3cZ/)... I always thought like it... (but not in this one : http://jsfiddle.net/2Z3cZ/2/) – cubitouch Jan 16 '14 at 22:17
  • thx @cubitouch for jsfiddle - when you say access DOM, do you mean the DOM of written out html or the DOM of any of the page. Taking for example the simple table in the question; I don't want to add anything to that DOM but would I be able to do DOM manipulation on the remainder of the page? – timpone Jan 16 '14 at 22:24
  • In that case, It seems harmless. But it seems to me like a bad practice as you work with text instead of objects. – cubitouch Jan 16 '14 at 22:26
2

Is there a some security element I'm missing?

The security risk is for them in that theirdomain.com trusting your domain's script code to not do anthing malicous. Your client script will run in the context of their domain and can do what it likes such as stealing cookies or embedding a key logger (not that you would do that of course). As long as they trust you, that is fine.

SilverlightFox
  • 32,436
  • 11
  • 76
  • 145